// The package export map does not expose its UMD/CSS entries. These are pinned
// package assets, not copied patches; the distributable preserves this src tree.
import engineUrl from '../../../node_modules/frappe-gantt/dist/frappe-gantt.umd.js?url';
import engineCss from '../../../node_modules/frappe-gantt/dist/frappe-gantt.css?raw';
import bridgeUrl from './chart-bridge.js?url&no-inline';
import { ganttTasks } from './chart-model';
import type { Plan } from './core';
import { isDate } from '../shared/dates';

export type TimelineView = 'Day' | 'Week' | 'Month';
interface ChartOptions {
  view: TimelineView;
  onChange: (id: string, start: string, end: string) => void;
  onReady: () => void;
  onError: () => void;
}

/**
 * Frappe 1.2.2 installs a document mouseup listener and has no destroy API.
 * Its whole document is isolated here; removing the iframe disposes that scope.
 * No task text, imported source or configuration is interpolated into code.
 */
export function mountTimeline(container: HTMLElement, plan: Plan, options: ChartOptions): () => void {
  const css = `${engineCss}\nhtml,body{margin:0;font-family:system-ui,sans-serif;background:#fff;color:#171717}body{--g-bar-color:#ded5ff;--g-bar-border:#6b46ff;--g-progress-color:#b9a8ff;--g-arrow-color:#746493;--g-text-dark:#171717;--g-text-light:#fff;--g-text-muted:#626262;--g-tick-color:#ededed;--g-row-color:#fff;--g-weekend-highlight-color:#f4f1fb} .gantt-container{height:430px!important;max-width:100vw;overflow:auto} .gantt .bar-label{font-size:12px!important} .gantt-container .extras .adjust{color:#171717}.gantt .bar-wrapper:focus-visible,.gantt-container:focus-visible{outline:3px solid #6b46ff;outline-offset:-3px}`;
  const htmlUrl = URL.createObjectURL(new Blob([
    `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src ${window.location.origin}; style-src 'unsafe-inline'; img-src data:; font-src 'none'; connect-src 'none'; base-uri 'none'; form-action 'none'"><style>${css}</style></head><body><main><svg id="chart" aria-label="Interactive project timeline"></svg></main><script src="${new URL(engineUrl, window.location.href)}"></script><script src="${new URL(bridgeUrl, window.location.href)}"></script></body></html>`,
  ], { type: 'text/html' }));
  const iframe = document.createElement('iframe');
  iframe.title = 'Project timeline — task dates can also be edited in the task list';
  iframe.className = 'et-planner-frame';
  iframe.setAttribute('sandbox', 'allow-scripts');
  iframe.setAttribute('referrerpolicy', 'no-referrer');
  iframe.src = htmlUrl;
  const receive = (event: MessageEvent) => {
    if (event.source !== iframe.contentWindow || !event.data || typeof event.data !== 'object') return;
    if (event.data.type === 'essential-plan-ready') iframe.contentWindow?.postMessage({ type: 'essential-plan-render', tasks: ganttTasks(plan.tasks), view: options.view }, '*');
    else if (event.data.type === 'essential-plan-mounted') options.onReady();
    else if (event.data.type === 'essential-plan-error') options.onError();
    else if (event.data.type === 'essential-plan-date') {
      const { id, start, end } = event.data;
      if (typeof id === 'string' && plan.tasks.some(task => task.id === id) && isDate(start) && isDate(end) && end >= start) options.onChange(id, start, end);
    }
  };
  window.addEventListener('message', receive);
  container.append(iframe);
  const timeout = window.setTimeout(options.onError, 15_000);
  const ready = (event: MessageEvent) => {
    if (event.source === iframe.contentWindow && ['essential-plan-mounted', 'essential-plan-error'].includes(event.data?.type)) window.clearTimeout(timeout);
  };
  window.addEventListener('message', ready);
  return () => {
    window.clearTimeout(timeout);
    window.removeEventListener('message', receive);
    window.removeEventListener('message', ready);
    iframe.remove();
    URL.revokeObjectURL(htmlUrl);
  };
}
