import { createDemoSnapshot, getPresets } from "../../../lib/demoData";
import { createLocalAccountSnapshot } from "../../../lib/localAccountSnapshot";
import { exportGood } from "../../../lib/goodFormat";
import { runAccountScan } from "../../../lib/scanner";
import type { AppSnapshot } from "../../../types/domain";
import type { CaptureOptions, CaptureResult, CaptureSourceInfo, SaveResultWithPath, ArtifactStoreLoadResult } from "../../../types/global";
import type {
  ArtifactRepositoryPort,
  CaptureRepositoryPort,
  OverlayRepositoryPort,
  RendererRepositories,
  ScanExportPort,
  SnapshotRepositoryPort,
} from "../../../infrastructure/repositories/rendererBridgeRepositoryTypes";
import type { Dispatch, SetStateAction } from "react";

export interface AppControllerContext {
  artifactRepo?: ArtifactRepositoryPort;
  captureRepo?: CaptureRepositoryPort;
  exportRepo?: ScanExportPort;
  overlayRepo?: OverlayRepositoryPort;
  snapshotRepo?: SnapshotRepositoryPort;
  isOverlay: boolean;
  selectedSourceId: string;
  snapshot: AppSnapshot;
  setCaptureSources: Dispatch<SetStateAction<CaptureSourceInfo[]>>;
  setSelectedSourceId: (value: string) => void;
  setTopbarStatus: (value: string) => void;
  setSnapshot: Dispatch<SetStateAction<AppSnapshot>>;
  setLatestCapture?: Dispatch<SetStateAction<CaptureResult | null>>;
  setIsScanning?: Dispatch<SetStateAction<boolean>>;
}

interface AppControllerUIState {
  isOverlay: boolean;
  selectedSourceId: string;
  snapshot: AppSnapshot;
  setCaptureSources: Dispatch<SetStateAction<CaptureSourceInfo[]>>;
  setSelectedSourceId: (value: string) => void;
  setTopbarStatus: (value: string) => void;
  setSnapshot: Dispatch<SetStateAction<AppSnapshot>>;
  setLatestCapture?: Dispatch<SetStateAction<CaptureResult | null>>;
  setIsScanning?: Dispatch<SetStateAction<boolean>>;
}

export function createAppControllerContext(
  repositories: RendererRepositories | null,
  uiState: AppControllerUIState,
): AppControllerContext {
  return {
    artifactRepo: repositories?.artifacts,
    captureRepo: repositories?.capture,
    exportRepo: repositories?.export,
    overlayRepo: repositories?.overlay,
    snapshotRepo: repositories?.snapshot,
    isOverlay: uiState.isOverlay,
    selectedSourceId: uiState.selectedSourceId,
    snapshot: uiState.snapshot,
    setCaptureSources: uiState.setCaptureSources,
    setSelectedSourceId: uiState.setSelectedSourceId,
    setTopbarStatus: uiState.setTopbarStatus,
    setSnapshot: uiState.setSnapshot,
    setLatestCapture: uiState.setLatestCapture,
    setIsScanning: uiState.setIsScanning,
  };
}

export function loadStoredArtifactSnapshotAction(context: AppControllerContext): Promise<void> {
  const { artifactRepo, setSnapshot } = context;
  if (!artifactRepo?.loadAll) {
    return Promise.resolve();
  }
  return artifactRepo.loadAll().then((result: ArtifactStoreLoadResult) => {
    if (!result?.ok || result.artifacts.length === 0) return;
    const nextSnapshot = createLocalAccountSnapshot(result.artifacts, getPresets());
    if (!nextSnapshot) return;
    setSnapshot(nextSnapshot);
  });
}

export async function initializeAppControllerStateAction(context: AppControllerContext): Promise<void> {
  const { snapshotRepo, isOverlay, setTopbarStatus, setSnapshot } = context;
  try {
    await loadStoredArtifactSnapshotAction(context);
    if (isOverlay) {
      return;
    }

    const stored = await snapshotRepo?.load();
    if (stored) {
      setSnapshot((current) =>
        current.artifacts.length > 0 && current.scanEvents[0]?.id === "local-db-loaded" ? current : stored,
      );
    }
    await refreshCaptureSourcesAction(context);
  } catch (error) {
    setTopbarStatus(error instanceof Error ? error.message : "Controller initialization failed.");
  }
}

export async function refreshCaptureSourcesAction(context: AppControllerContext): Promise<void> {
  const { captureRepo, selectedSourceId, setCaptureSources, setSelectedSourceId, setTopbarStatus } = context;
  if (!captureRepo?.listSources) {
    setTopbarStatus("Electron bridge missing. Die Browser-Vorschau kann Genshin nicht scannen - Electron-App verwenden.");
    return;
  }
  try {
    const sources = await captureRepo.listSources();
    setCaptureSources(sources);
    const currentStillExists = sources.some((source: CaptureSourceInfo) => source.id === selectedSourceId);
    const genshinCandidate = sources.find((source: CaptureSourceInfo) => source.isGenshinCandidate);
    const current = currentStillExists ? sources.find((source: CaptureSourceInfo) => source.id === selectedSourceId) : null;
    const preferred = genshinCandidate ?? current ?? sources.find((source: CaptureSourceInfo) => source.id.startsWith("screen:")) ?? sources[0];
    if (preferred && preferred.id !== selectedSourceId) setSelectedSourceId(preferred.id);
    setTopbarStatus(
      `${sources.length} capture sources found${preferred?.isGenshinCandidate ? "; Genshin candidate selected" : ""}. Keep Genshin visible on the captured screen.`,
    );
  } catch (error) {
    setTopbarStatus(error instanceof Error ? error.message : "Could not list capture sources.");
  }
}

export async function captureSelectedSourceAction(
  context: AppControllerContext,
  delayMs = 0,
  focusGenshin = false,
  options?: CaptureOptions,
): Promise<CaptureResult | null> {
  const { captureRepo, selectedSourceId, setTopbarStatus, setLatestCapture } = context;
  if (!captureRepo?.captureSource) {
    setTopbarStatus("Electron bridge missing. Capture only works inside the Electron app.");
    return null;
  }
  if (!selectedSourceId) {
    setTopbarStatus("No capture source selected. Press Sources after Genshin is open.");
    return null;
  }
  if (!setLatestCapture) {
    setTopbarStatus("Capture state cannot be updated.");
    return null;
  }
  try {
    if (delayMs > 0) {
      setTopbarStatus(`Capture in ${Math.round(delayMs / 1000)}s. Put Genshin in front and leave it visible.`);
    }
    const capture = await captureRepo.captureSource(selectedSourceId, delayMs, focusGenshin, options);
    setLatestCapture(capture);
    const ocrStatus = capture.ocrSkipped
      ? "OCR skipped for fast scan."
      : capture.ocrTimedOut
        ? "OCR timed out; review sample needed."
        : "OCR handoff is next.";
    setTopbarStatus(`Captured ${capture.name} at ${capture.width}x${capture.height}. ${ocrStatus}`);
    return capture;
  } catch (error) {
    setTopbarStatus(error instanceof Error ? error.message : "Capture failed.");
    return null;
  }
}

export async function runDemoScanAction(
  context: AppControllerContext,
  captureSelectedSource: () => Promise<CaptureResult | null>,
): Promise<void> {
  const { snapshotRepo, setSnapshot, setIsScanning, setTopbarStatus } = context;
  if (!setIsScanning) {
    return;
  }
  setIsScanning(true);
  try {
    await captureSelectedSource();
    const next = await (snapshotRepo?.runMockScan() ?? Promise.resolve(null));
    const resolved = next ?? (await runAccountScan());
    setSnapshot(resolved);
    await snapshotRepo?.save(resolved);
  } catch (error) {
    setTopbarStatus(error instanceof Error ? error.message : "Demo scan failed.");
  } finally {
    setIsScanning(false);
  }
}

export function createInitialSnapshot(): AppSnapshot {
  return createDemoSnapshot();
}

export function exportCurrentGoodAction(context: AppControllerContext): Promise<void> {
  const { exportRepo, snapshot, setTopbarStatus } = context;
  if (!exportRepo?.exportGood) {
    setTopbarStatus("GOOD-Export ist nur in der Electron-App verfuegbar.");
    return Promise.resolve();
  }
  if (snapshot.artifacts.length === 0) {
    setTopbarStatus("Keine Artifacts zum Exportieren vorhanden.");
    return Promise.resolve();
  }
  return exportRepo
    .exportGood(exportGood(snapshot.artifacts))
    .then((result: SaveResultWithPath) => {
      setTopbarStatus(result.ok ? `GOOD exportiert: ${result.path}` : "GOOD-Export fehlgeschlagen.");
    });
}

export async function showOverlayAction(context: AppControllerContext): Promise<void> {
  const { overlayRepo, setTopbarStatus } = context;
  if (!overlayRepo?.show) {
    setTopbarStatus("Overlay braucht die Electron-Bridge.");
    return;
  }
  try {
    await overlayRepo.show();
  } catch {
    setTopbarStatus("Overlay konnte nicht gestartet werden.");
  }
}
