

class RestClient {
  constructor({ baseURL = '', headers = {} } = {}) {
    this.baseURL = baseURL;
    this.headers = { ...headers };

    // Interceptor containers
    this.interceptors = {
      request: {
        handlers: [],
        use: (fn) => {
          this.interceptors.request.handlers.push(fn);
        }
      },
      response: {
        handlers: [],
        use: (successFn, errorFn) => {
          this.interceptors.response.handlers.push({ success: successFn, error: errorFn });
        }
      }
    };
  }

  // Core request method
  request(config) {
    // Merge defaults
    const cfg = {
      method: 'GET',
      url: '',
      data: null,
      headers: {},
      ...config
    };
    cfg.headers = { ...this.headers, ...cfg.headers };

    // Apply request interceptors
    let chain = Promise.resolve(cfg);
    this.interceptors.request.handlers.forEach((fn) => {
      chain = chain.then(fn);
    });

    // Perform fetch
    chain = chain.then((c) => {
      const url = this.baseURL + c.url;
      const options = { method: c.method, headers: c.headers };
      if (c.data != null) {
        options.body = JSON.stringify(c.data);
        if (!options.headers['Content-Type']) {
          options.headers['Content-Type'] = 'application/json';
        }
      }
      return fetch(url, options).then(async (response) => {
        const text = await response.text();
        let data;
        try {
          data = JSON.parse(text);
        } catch (e) {
          data = text;
        }
        const result = {
          data,
          status: response.status,
          statusText: response.statusText,
          headers: RestClient._parseHeaders(response.headers),
          config: c,
          request: response
        };
        if (!response.ok) {
          return Promise.reject(result);
        }
        return result;
      });
    });

    // Apply response interceptors
    this.interceptors.response.handlers.forEach(({ success, error }) => {
      chain = chain.then(success, error);
    });

    return chain;
  }

  // Helper methods for HTTP verbs
  get(url, config) {
    return this.request({ ...config, method: 'GET', url });
  }
  delete(url, config) {
    return this.request({ ...config, method: 'DELETE', url });
  }
  head(url, config) {
    return this.request({ ...config, method: 'HEAD', url });
  }
  options(url, config) {
    return this.request({ ...config, method: 'OPTIONS', url });
  }
  post(url, data, config) {
    return this.request({ ...config, method: 'POST', url, data });
  }
  put(url, data, config) {
    return this.request({ ...config, method: 'PUT', url, data });
  }
  patch(url, data, config) {
    return this.request({ ...config, method: 'PATCH', url, data });
  }

  // Utility to parse Fetch headers into an object
  static _parseHeaders(headers) {
    const result = {};
    for (const [key, value] of headers.entries()) {
      result[key] = value;
    }
    return result;
  }
}






class Njet extends HTMLElement {
    static _root = null
    static showDialog = null

    get isRoot() {
        return Njet._root === this
    }

    get root() {
        return Njet._root
    }

    get rest() {
        return Njet._root._rest
    }

    _subscriptions = {}
    _elements = []
    _rest = null

    match(args) {
        return Object.entries(args).every(([key, value]) => this[key] === value);
    }

    set(key, value) {
        this.dataset[key] = value
    }

    get(key, defaultValue) {
        if (this.dataset[key]) {
            return this.dataset[key]
        }
        if (defaultValue === undefined) {
            return
        }
        this.dataset[key] = defaultValue
        return this.dataset[key]
    }

    showDialog(args){

       // const dialog = this.createComponent('njet-dialog', args)
   //     dialog.show()
     //   return dialog()
    }

    find(args) {
        for (let element of this.root._elements) {
            if (element.match(args)) {
                return element
            }
        }
        return null
    }

    findAll(args) {
        return this.root._elements.filter(element => element.match(args))
    }

    subscribe(event, callback) {
        if (!this.root._subscriptions[event]) {
            this.root._subscriptions[event] = []
        }
        this.root._subscriptions[event].push(callback)
    }

    publish(event, data) {
        if (this.root._subscriptions[event]) {
            this.root._subscriptions[event].forEach(callback => callback(data))
        }
    }

    static registerComponent(name, component) {
        customElements.define(name, component);
    }

    constructor(config = {}) {
        super();
        if (!Njet._root) {
            Njet._root = this
            Njet._rest = new RestClient({ baseURL: config.baseURL || null })
        }
        this.root._elements.push(this)
        this.classList.add('njet');
        this.config = config;
        this.render.call(this);
        this.initProps(config);
        if (typeof this.construct === 'function')
            this.construct.call(this)
    }

    initProps(config) {
        const props = Object.keys(config)
        props.forEach(prop => {
            if (config[prop] !== undefined) {
                this[prop] = config[prop];
            }
        });
        if (config.classes) {
            this.classList.add(...config.classes);
        }
    }

    duplicate() {
        const duplicatedConfig = { ...this.config };
        if (duplicatedConfig.items) {
            duplicatedConfig.items = duplicatedConfig.items.map(item => {
                return typeof item.duplicate === 'function' ? item.duplicate() : item;
            });
        }
        return new this.constructor(duplicatedConfig);
    }

    set width(val) {
        this.style.width = typeof val === 'number' ? `${val}px` : val;
    }

    get width() { return this.style.width; }

    set height(val) {
        this.style.height = typeof val === 'number' ? `${val}px` : val;
    }

    get height() { return this.style.height; }

    set left(val) {
        this.style.position = 'absolute';
        this.style.left = typeof val === 'number' ? `${val}px` : val;
    }

    get left() { return this.style.left; }

    set top(val) {
        this.style.position = 'absolute';
        this.style.top = typeof val === 'number' ? `${val}px` : val;
    }

    get top() { return this.style.top; }

    set opacity(val) { this.style.opacity = val; }
    get opacity() { return this.style.opacity; }

    set disabled(val) { this.toggleAttribute('disabled', !!val); }
    get disabled() { return this.hasAttribute('disabled'); }

    set visible(val) { this.style.display = val ? '' : 'none'; }
    get visible() { return this.style.display !== 'none'; }

    render() {}
}

class Component extends Njet {}

class NjetPanel extends Component {
    render() {
        this.innerHTML = '';
        const { title, items = [] } = this.config;
        this.style.border = '1px solid #ccc';
        this.style.padding = '10px';
        if (title) {
            const header = document.createElement('h3');
            header.textContent = title;
            this.appendChild(header);
        }
        items.forEach(item => this.appendChild(item));
    }
}
Njet.registerComponent('njet-panel', NjetPanel);

class NjetButton extends Component {
    render() {
        this.classList.add('njet-button');
        this.innerHTML = '';
        const button = document.createElement('button');
        button.textContent = this.config.text || 'Button';
        if (typeof this.config.handler === 'function') {
            button.addEventListener('click', (event) => this.config.handler.call(this));
        }
        const observer = new MutationObserver(() => {
            button.disabled = this.disabled;
        });
        observer.observe(this, { attributes: true, attributeFilter: ['disabled'] });
        button.disabled = this.disabled;
        this.appendChild(button);
    }
}
Njet.registerComponent('njet-button', NjetButton);

class NjetDialog extends Component {
    render() {
        this.innerHTML = '';
        const { title, content, primaryButton, secondaryButton } = this.config;
        this.classList.add('njet-dialog');
        this.style.position = 'fixed';
        this.style.top = '50%';
        this.style.left = '50%';
        this.style.transform = 'translate(-50%, -50%)';
        this.style.padding = '20px';
        this.style.border = '1px solid #444';
        this.style.backgroundColor = '#fff';
        this.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
        this.style.minWidth = '300px';
        if (title) {
            const header = document.createElement('h2');
            header.textContent = title;
            this.appendChild(header);
        }
        if (content) {
            const body = document.createElement('div');
            body.innerHTML = content;
            this.appendChild(body);
        }
        const buttonContainer = document.createElement('div');
        buttonContainer.style.marginTop = '20px';
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'flenjet-end';
        buttonContainer.style.gap = '10px';
        if (secondaryButton) {
            const secondary = new NjetButton(secondaryButton);
            buttonContainer.appendChild(secondary);
        }
        if (primaryButton) {
            const primary = new NjetButton(primaryButton);
            buttonContainer.appendChild(primary);
        }
        this.appendChild(buttonContainer);
    }

    show(){
        document.body.appendChild(this)
    }
}
Njet.registerComponent('njet-dialog', NjetDialog);

class NjetGrid extends Component {
    render() {
        this.classList.add('njet-grid');
        this.innerHTML = '';
        const table = document.createElement('table');
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';
        const data = this.config.data || [];
        data.forEach(row => {
            const tr = document.createElement('tr');
            Object.values(row).forEach(cell => {
                const td = document.createElement('td');
                td.textContent = cell;
                td.style.border = '1px solid #ddd';
                td.style.padding = '4px';
                tr.appendChild(td);
            });
            table.appendChild(tr);
        });
        this.appendChild(table);
    }
}
Njet.registerComponent('njet-grid', NjetGrid);
/*
const button = new NjetButton({
    classes: ['my-button'],
    text: 'Shared',
    tag: 'shared',
    width: 120,
    height: 30,
    handler() {
        this.root.findAll({ tag: 'shared' }).forEach(e => {
            e.disabled = !e.disabled;
        });
    }
});

const button2 = new NjetButton({
    classes: ['my-button'],
    text: 'Single',
    iValue: 0,
    width: 120,
    height: 30,
    handler() {
        this.iValue++;
        const panel = this.closest('njet-panel');
        if (panel) {
            const h3 = panel.querySelector('h3');
            if (h3) h3.textContent = `Click ${this.iValue}`;
        }
        this.publish("btn2Click", `Click ${this.iValue}`);
    }
});

const grid = new NjetGrid({
    data: [
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' }
    ],
    width: '100%',
    visible: true
});

const panel = new NjetPanel({
    title: 'My Panel',
    items: [button, grid, button2],
    left: 50,
    top: 50,
    construct: function () {
        this.subscribe('btn2Click', (data) => {
            this._title = data
        });
    }
});

document.body.appendChild(panel);

const panelClone = panel.duplicate();
const panell = panelClone.duplicate();
panell.left = 120;
panell.width = 300;
panelClone.appendChild(panell);
panelClone.left = 300;
panelClone.top = 50;
document.body.appendChild(panelClone);

const dialog = new NjetDialog({
    title: 'Confirm Action',
    content: 'Are you sure you want to continue?',
    primaryButton: {
        text: 'Yes',
        handler: function () {
            alert('Confirmed');
            this.closest('njet-dialog').remove();
        }
    },
    secondaryButton: {
        text: 'Cancel',
        handler: function () {
            this.closest('njet-dialog').remove();
        }
    }
});

document.body.appendChild(dialog);
*/

class NjetComponent extends Component {}
    const njet = Njet;
njet.showDialog = function(args){
    const dialog = new NjetDialog(args) 
    dialog.show()
    return dialog 
}

window.njet = njet 

export { Njet, NjetButton, NjetPanel, NjetDialog, NjetGrid, NjetComponent, njet};
