import { showAsyncFlash } from '/js/components/app-async-flash.js';
import { getJson, postForm } from '/js/core/app-http.js';
import { createListPageModule } from '/js/core/app-list-page-module.js';
import { escapeHtml } from '/js/pages/app-list-utils.js';

createListPageModule({
  configId: 'helpdesk-updates',
  moduleId: 'helpdesk-updates',
  missingGridMessage: 'Helpdesk updates grid init failed: Grid.js missing',
  initErrorMessage: 'Helpdesk updates grid init failed',
  setup: ({ config, gridjs, appBase, initListPage }) => {
    const labels = config.labels || {};
    const canManage = config.canManage || false;

    const listResult = initListPage({
      grid: {
        gridjs,
        container: '#helpdesk-updates-grid',
        dataUrl: config.dataUrl || 'helpdesk/updates-data',
        appBase,
        columns: [
          {
            name: labels.ticketNo || 'Ticket',
            sort: false,
            formatter: (cell) => {
              const no = escapeHtml(String(cell?.no || ''));
              const url = String(cell?.url || '').trim();
              if (no === '') return gridjs.html('<span class="text-muted">—</span>');
              if (url === '') return gridjs.html(`<span>${no}</span>`);
              return gridjs.html(`<a href="${escapeHtml(url)}">${no}</a>`);
            },
          },
          {
            name: labels.ticketDescription || 'Description',
            sort: false,
            formatter: (cell) => {
              const text = String(cell || '').trim();
              if (text === '') {
                return gridjs.html('<span class="text-muted">—</span>');
              }
              const escaped = escapeHtml(text);
              return gridjs.html(`<span class="app-cell-note" title="${escaped}">${escaped}</span>`);
            },
          },
          {
            name: labels.ticketState || 'Ticket status',
            sort: false,
            formatter: (cell) => {
              const label = escapeHtml(cell?.label || '');
              const variant = cell?.variant || 'neutral';
              return gridjs.html(`<span class="badge" data-variant="${escapeHtml(variant)}">${label}</span>`);
            },
          },
          {
            name: labels.assignment || 'Assignment',
            sort: false,
            formatter: (cell) => {
              const label = escapeHtml(cell?.label || '');
              const variant = cell?.variant || 'neutral';
              return gridjs.html(`<span class="badge" data-variant="${escapeHtml(variant)}">${label}</span>`);
            },
          },
          {
            name: labels.actions || '',
            sort: false,
            formatter: (cell) => {
              if (!cell) return '';
              let buttons = '';
              if (canManage) {
                // raw-html-ok: all values passed through escapeHtml, cell data is from our own API
                const data = escapeHtml(JSON.stringify(cell));
                const buttonLabel = cell.status === 'open'
                  ? escapeHtml(labels.assign || 'Assign')
                  : escapeHtml(labels.edit || 'Edit');
                const icon = cell.status === 'open' ? 'bi-link-45deg' : 'bi-pencil';
                buttons += `<button type="button" class="secondary outline small" data-update-assign='${data}' data-tooltip="${buttonLabel}" data-tooltip-pos="top" aria-label="${buttonLabel}"><i class="bi ${icon}"></i></button>`;
              }
              const giteaUrl = String(cell.gitea_path || '').trim();
              if (giteaUrl !== '') {
                const giteaLabel = escapeHtml(labels.giteaLink || 'Gitea');
                buttons += `<a href="${escapeHtml(giteaUrl)}" target="_blank" rel="noopener" role="button" class="secondary outline small" data-tooltip="${giteaLabel}" data-tooltip-pos="top" aria-label="${giteaLabel}"><i class="bi bi-box-arrow-up-right"></i></a>`;
              }
              if (buttons === '') return '';
              return gridjs.html(`<span class="app-inline-actions">${buttons}</span>`);
            },
          },
          {
            name: labels.category || 'Type',
            sort: false,
            formatter: (cell) => {
              const label = escapeHtml(cell?.label || '');
              const variant = cell?.variant || 'neutral';
              return gridjs.html(`<span class="badge" data-variant="${escapeHtml(variant)}">${label}</span>`);
            },
          },
          {
            name: labels.debitor || 'Customer',
            sort: false,
            formatter: (cell) => {
              const name = escapeHtml(String(cell?.name || ''));
              const url = String(cell?.url || '').trim();
              if (name === '') return gridjs.html('<span class="text-muted">—</span>');
              const style = 'display:inline-block;max-width:20ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom';
              if (url === '') return gridjs.html(`<span style="${style}" title="${name}">${name}</span>`);
              return gridjs.html(`<a href="${escapeHtml(url)}" style="${style}" title="${name}">${name}</a>`);
            },
          },
          { name: labels.domain || 'Domain', sort: false },
          { name: labels.createdOn || 'Created', sort: false },
        ],
        paginationLimit: 50,
        language: config.gridLang || {},
        mapData: (data) => {
          const rows = data.rows || data.data || [];
          return rows.map((row) => [
            { no: row.ticket_no || '', url: row.ticket_url || '' },
            row.ticket_description || '',
            { label: row.ticket_state_label || '', variant: row.ticket_state_variant || 'neutral' },
            { label: row.status_label || '', variant: row.status_variant || 'neutral' },
            {
              ticket_no: row.ticket_no || '',
              debitor_no: row.debitor_no || '',
              debitor_name: row.debitor_name || '',
              category_code: row.category_code || '',
              domain_no: row.domain_no || '',
              domain_url: row.domain_url || '',
              gitea_path: row.gitea_path || '',
              notes: row.notes || '',
              status: row.status || 'open',
            },
            { label: row.category_label || '', variant: row.category_variant || 'neutral' },
            { name: row.debitor_name || '', url: row.debitor_url || '' },
            row.domain_url || '',
            row.created_on || '',
          ]);
        },
        search: config.gridSearch || null,
        filterSchema: config.filterSchema || [],
        urlSync: true,
      },
      filters: {
        mode: 'drawer',
        chipMeta: config.filterChipMeta || {},
        watchInputs: ['#helpdesk-updates-search-input'],
      },
    });

    const gridConfig = listResult?.gridConfig || null;
    if (!gridConfig) {
      return null;
    }

    const refreshButton = document.getElementById('updates-refresh-button');
    if (refreshButton) {
      refreshButton.addEventListener('click', async () => {
        refreshButton.disabled = true;
        refreshButton.setAttribute('aria-busy', 'true');
        try {
          const refreshUrl = new URL(config.dataUrl, appBase);
          refreshUrl.searchParams.set('refresh', '1');
          await getJson(refreshUrl.toString());
          gridConfig?.grid?.forceRender();
        } catch {
          showAsyncFlash('error', labels.refreshError || labels.assignError || 'Refresh failed');
        } finally {
          refreshButton.disabled = false;
          refreshButton.removeAttribute('aria-busy');
        }
      });
    }

    if (!canManage) {
      return gridConfig;
    }

    const dialog = document.getElementById('update-assign-dialog');
    const form = document.getElementById('update-assign-form');
    const contextEl = document.getElementById('update-assign-context');
    const domainSelect = document.getElementById('update-assign-domain');
    const giteaInput = document.getElementById('update-assign-gitea');
    const notesInput = document.getElementById('update-assign-notes');
    const ticketNoInput = document.getElementById('update-assign-ticket-no');
    const debitorNoInput = document.getElementById('update-assign-debitor-no');
    const debitorNameInput = document.getElementById('update-assign-debitor-name');
    const categoryCodeInput = document.getElementById('update-assign-category-code');
    const domainUrlInput = document.getElementById('update-assign-domain-url');
    const submitButton = document.getElementById('update-assign-submit');

    if (!dialog || !form || !domainSelect || !domainUrlInput || !submitButton) {
      return gridConfig;
    }

    const closeDialog = () => {
      try { dialog.close(); } catch { /* no-op */ }
      document.body.classList.remove('modal-is-open');
    };

    dialog.querySelectorAll('[data-update-assign-close]').forEach((button) => {
      button.addEventListener('click', (event) => {
        event.preventDefault();
        closeDialog();
      });
    });
    dialog.addEventListener('cancel', (event) => {
      event.preventDefault();
      closeDialog();
    });
    dialog.addEventListener('click', (event) => {
      if (event.target === dialog) {
        closeDialog();
      }
    });

    domainSelect.addEventListener('change', () => {
      const selected = domainSelect.options[domainSelect.selectedIndex];
      domainUrlInput.value = selected?.dataset?.url || '';
    });

    const populateDomainSelect = (domains, preselectedNo) => {
      domainSelect.textContent = '';
      if (!Array.isArray(domains) || domains.length === 0) {
        const opt = document.createElement('option');
        opt.value = '';
        opt.textContent = labels.noDomains || 'No domains found';
        domainSelect.appendChild(opt);
      } else {
        const placeholder = document.createElement('option');
        placeholder.value = '';
        placeholder.textContent = labels.selectDomain || 'Select domain...';
        domainSelect.appendChild(placeholder);
        for (const domain of domains) {
          const opt = document.createElement('option');
          opt.value = domain.value || '';
          opt.textContent = domain.label || domain.value || '';
          opt.dataset.url = domain.url || '';
          if (preselectedNo && domain.value === preselectedNo) {
            opt.selected = true;
            domainUrlInput.value = domain.url || '';
          }
          domainSelect.appendChild(opt);
        }
      }
      domainSelect.disabled = false;
    };

    document.addEventListener('click', async (event) => {
      const button = event.target.closest('[data-update-assign]');
      if (!button) {
        return;
      }

      let data;
      try {
        data = JSON.parse(button.dataset.updateAssign);
      } catch {
        return;
      }

      ticketNoInput.value = data.ticket_no || '';
      debitorNoInput.value = data.debitor_no || '';
      debitorNameInput.value = data.debitor_name || '';
      categoryCodeInput.value = data.category_code || '';
      giteaInput.value = data.gitea_path || '';
      notesInput.value = data.notes || '';
      domainUrlInput.value = data.domain_url || '';

      const categoryDisplay = data.category_code === 'UPDATE-HF'
        ? (labels.hotfix || 'Hotfix')
        : (labels.update || 'Update');
      contextEl.textContent = `${data.ticket_no} - ${data.debitor_name} - ${categoryDisplay}`;

      domainSelect.textContent = '';
      const loadingOpt = document.createElement('option');
      loadingOpt.value = '';
      loadingOpt.textContent = labels.loadingDomains || 'Loading...';
      domainSelect.appendChild(loadingOpt);
      domainSelect.disabled = true;

      document.body.classList.add('modal-is-open');
      dialog.showModal();

      try {
        const domainsUrl = new URL(config.domainsDataUrl, appBase);
        domainsUrl.searchParams.set('debitor_no', data.debitor_no);
        const domains = await getJson(domainsUrl.toString());
        populateDomainSelect(domains, data.domain_no);
      } catch {
        populateDomainSelect([], null);
      }
    });

    form.addEventListener('submit', async (event) => {
      event.preventDefault();
      submitButton.disabled = true;
      submitButton.setAttribute('aria-busy', 'true');

      const formData = new URLSearchParams(new FormData(form));
      if (config.csrfKey) {
        formData.set(config.csrfKey, config.csrfToken || '');
      }

      try {
        const result = await postForm(new URL(config.assignUrl, appBase).toString(), formData);
        if (result?.ok === true) {
          closeDialog();
          gridConfig?.grid?.forceRender();
          showAsyncFlash('success', labels.assignSuccess || labels.saved || 'Saved');
        } else {
          const errorMsg = result?.errors?.general || labels.assignError || 'Failed to assign';
          showAsyncFlash('error', errorMsg);
        }
      } catch (error) {
        const errorMsg = error?.payload?.errors?.general || labels.assignError || 'Failed to assign';
        showAsyncFlash('error', errorMsg);
      } finally {
        submitButton.disabled = false;
        submitButton.removeAttribute('aria-busy');
      }
    });

    return gridConfig;
  },
});
