import browser from 'webextension-polyfill';
import {
  ChatGptProductStateError,
  ChatGptWebAdapter,
  HostUiChangedError,
  type ChatGptInspection,
  type ChatGptWaitCondition,
} from '@platform-modules/chatgpt-web-adapter';
import { createManagedOverlay } from './overlay.js';
import { OVERLAY_MESSAGE_KIND, UI_MESSAGE_KIND, type OverlayUpdate } from './ui-model.js';

const CONTENT_KIND = 'chatgpt-orchestrator.content' as const;
const STATE_KIND = 'chatgpt-orchestrator.content-state' as const;
const BOOTSTRAP_KIND = 'chatgpt-orchestrator.content-bootstrap' as const;

void browser.runtime.sendMessage({ kind: 'chatgpt-orchestrator.wake' }).catch(() => undefined);

interface ContentRequest {
  kind: typeof CONTENT_KIND;
  action: 'inspect' | 'submit' | 'steer' | 'wait';
  prompt?: string;
  condition?: ChatGptWaitCondition;
  timeoutMs?: number;
}

let adapter: ChatGptWebAdapter | null = null;
let overlay: ReturnType<typeof createManagedOverlay> | null = null;
let disposeObservation: (() => void) | null = null;
let lastPublished: string | null = null;

function ensureManagedRuntime(): ChatGptWebAdapter {
  const currentAdapter = adapter ??= new ChatGptWebAdapter();
  overlay ??= createManagedOverlay(document, (action, worker, enabled) => {
    void browser.runtime.sendMessage({
      kind: UI_MESSAGE_KIND,
      action,
      workerId: worker.workerId,
      ...(action === 'set-auto-resume' ? { enabled: Boolean(enabled) } : {}),
    }).catch(() => undefined);
  });
  disposeObservation ??= currentAdapter.observe(publishInspection, { reconcileIntervalMs: 5_000 });
  return currentAdapter;
}

function publishInspection(inspection: ChatGptInspection): void {
  const signature = JSON.stringify([
    inspection.state,
    inspection.conversationId,
    inspection.composerReady,
    inspection.generating,
    inspection.issue?.code ?? null,
    inspection.issue?.retryAt ?? null,
    inspection.error,
    inspection.url,
    inspection.assistantOutputTail,
    inspection.assistantOutputTruncated,
  ]);
  if (signature === lastPublished) return;
  lastPublished = signature;
  void browser.runtime.sendMessage({ kind: STATE_KIND, inspection }).catch(() => undefined);
}

void browser.runtime.sendMessage({ kind: BOOTSTRAP_KIND })
  .then((response: unknown) => {
    if ((response as { managed?: boolean } | null)?.managed === true) ensureManagedRuntime();
  })
  .catch(() => undefined);

browser.runtime.onMessage.addListener((unknownMessage: unknown) => {
  const overlayMessage = unknownMessage as Partial<OverlayUpdate>;
  if (overlayMessage.kind === OVERLAY_MESSAGE_KIND) {
    ensureManagedRuntime();
    overlay?.update(overlayMessage.worker ?? null, overlayMessage.overlayVisible === true);
    return undefined;
  }

  const message = unknownMessage as Partial<ContentRequest>;
  if (message.kind !== CONTENT_KIND) return undefined;

  const execute = async (): Promise<Record<string, unknown>> => {
    const currentAdapter = ensureManagedRuntime();
    try {
      if (message.action === 'inspect') {
        const inspection = currentAdapter.inspect();
        publishInspection(inspection);
        return { ok: true, inspection };
      }
      if (message.action === 'submit' && typeof message.prompt === 'string') {
        await currentAdapter.submitPrompt(message.prompt);
        const inspection = currentAdapter.inspect();
        publishInspection(inspection);
        return { ok: true, inspection };
      }
      if (message.action === 'steer' && typeof message.prompt === 'string') {
        await currentAdapter.submitSteering(message.prompt);
        const inspection = currentAdapter.inspect();
        publishInspection(inspection);
        return { ok: true, inspection };
      }
      if (message.action === 'wait' && typeof message.condition === 'string' && typeof message.timeoutMs === 'number') {
        const inspection = await currentAdapter.waitFor(message.condition, message.timeoutMs);
        publishInspection(inspection);
        return { ok: true, inspection };
      }
      return { ok: false, code: 'INVALID_REQUEST', error: 'Unsupported content-script request.' };
    } catch (error) {
      if (error instanceof ChatGptProductStateError) {
        return { ok: false, code: error.code, error: error.message, retryAt: error.retryAt };
      }
      if (error instanceof HostUiChangedError) {
        return { ok: false, code: error.code, error: error.message };
      }
      return { ok: false, code: 'INTERNAL_ERROR', error: error instanceof Error ? error.message : 'Unknown content-script error.' };
    }
  };

  return execute();
});
