import { useCallback, useEffect, useRef, useState } from 'react';
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
import { terminalBridge } from '../lib/terminalBridge';
import type {
  BackgroundJobEvent,
  BackgroundJobKind,
  BackgroundJobSnapshot,
  StartBackgroundJobRequest,
} from '../types/terminal';

export interface ActiveBackgroundJob {
  snapshot: BackgroundJobSnapshot;
  startedAt: Date;
}

export const useBackgroundJobs = () => {
  const [activeJobs, setActiveJobs] = useState<Map<string, ActiveBackgroundJob>>(new Map());
  const [recentCompleted, setRecentCompleted] = useState<BackgroundJobSnapshot[]>([]);
  const unlistenRef = useRef<UnlistenFn | null>(null);

  useEffect(() => {
    let disposed = false;

    const setup = async () => {
      const unlisten = await listen<BackgroundJobEvent>(
        'background_job_event',
        (event) => {
          if (disposed) return;

          const payload = event.payload;

          setActiveJobs((prev) => {
            const next = new Map(prev);
            const existing = next.get(payload.jobId);

            if (
              payload.status === 'completed' ||
              payload.status === 'failed' ||
              payload.status === 'cancelled'
            ) {
              next.delete(payload.jobId);

              const snapshot: BackgroundJobSnapshot = {
                jobId: payload.jobId,
                workspaceId: payload.workspaceId,
                kind: payload.kind,
                status: payload.status,
                progress: payload.progress,
                label: payload.label,
                result: payload.result,
                error: payload.error,
                createdAt: existing?.snapshot.createdAt ?? new Date().toISOString(),
                updatedAt: new Date().toISOString(),
              };

              setRecentCompleted((prevCompleted) => {
                const nextCompleted = [snapshot, ...prevCompleted].slice(0, 10);
                return nextCompleted;
              });
            } else if (existing) {
              next.set(payload.jobId, {
                snapshot: {
                  ...existing.snapshot,
                  status: payload.status,
                  progress: payload.progress ?? existing.snapshot.progress,
                  label: payload.label ?? existing.snapshot.label,
                  error: payload.error ?? existing.snapshot.error,
                  updatedAt: new Date().toISOString(),
                },
                startedAt: existing.startedAt,
              });
            }

            return next;
          });
        },
      );

      if (!disposed) {
        unlistenRef.current = unlisten;
      } else {
        unlisten();
      }
    };

    void setup();

    return () => {
      disposed = true;
      unlistenRef.current?.();
      unlistenRef.current = null;
    };
  }, []);

  const startJob = useCallback(
    async (workspaceId: string, kind: BackgroundJobKind, params?: Record<string, unknown>) => {
      const request: StartBackgroundJobRequest = {
        workspaceId,
        kind,
        params,
      };

      const snapshot = await terminalBridge.startBackgroundJob(request);

      setActiveJobs((prev) => {
        const next = new Map(prev);
        next.set(snapshot.jobId, {
          snapshot,
          startedAt: new Date(),
        });
        return next;
      });

      return snapshot;
    },
    [],
  );

  const cancelJob = useCallback(async (jobId: string) => {
    await terminalBridge.cancelBackgroundJob({ jobId });
  }, []);

  const clearRecentCompleted = useCallback(() => {
    setRecentCompleted([]);
  }, []);

  return {
    activeJobs: Array.from(activeJobs.values()),
    recentCompleted,
    startJob,
    cancelJob,
    clearRecentCompleted,
  };
};
