import type { JobSource } from "@shared/types";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
  DEFAULT_PIPELINE_SOURCES,
  orderedSources,
  PIPELINE_SOURCES_STORAGE_KEY,
} from "./constants";

const resolveAllowedSources = (enabledSources?: readonly JobSource[]) =>
  enabledSources && enabledSources.length > 0
    ? (enabledSources as JobSource[])
    : DEFAULT_PIPELINE_SOURCES;

const mergeAllowedSources = (
  sources: JobSource[],
  allowedSources: JobSource[],
): JobSource[] => {
  const kept = sources.filter((value) => allowedSources.includes(value));
  const missing = allowedSources.filter((value) => !kept.includes(value));
  const merged = [...kept, ...missing];
  return merged.length > 0 ? merged : [...allowedSources];
};

const sourcesMatch = (left: JobSource[], right: JobSource[]) =>
  left.length === right.length &&
  left.every((value, index) => value === right[index]);

export const usePipelineSources = (enabledSources?: readonly JobSource[]) => {
  const allowedSources = useMemo(
    () => resolveAllowedSources(enabledSources),
    [enabledSources],
  );
  const [pipelineSources, setPipelineSources] = useState<JobSource[]>(() => {
    try {
      const raw = localStorage.getItem(PIPELINE_SOURCES_STORAGE_KEY);
      if (!raw) return mergeAllowedSources([], allowedSources);
      const parsed = JSON.parse(raw) as unknown;
      if (!Array.isArray(parsed))
        return mergeAllowedSources([], allowedSources);
      const next = parsed.filter((value): value is JobSource =>
        orderedSources.includes(value as JobSource),
      );
      return mergeAllowedSources(next, allowedSources);
    } catch {
      return mergeAllowedSources([], allowedSources);
    }
  });

  useEffect(() => {
    setPipelineSources((current) => {
      const normalized = mergeAllowedSources(current, allowedSources);
      return sourcesMatch(current, normalized) ? current : normalized;
    });
  }, [allowedSources]);

  useEffect(() => {
    try {
      localStorage.setItem(
        PIPELINE_SOURCES_STORAGE_KEY,
        JSON.stringify(pipelineSources),
      );
    } catch {
      // Ignore localStorage errors
    }
  }, [pipelineSources]);

  const toggleSource = useCallback(
    (source: JobSource, checked: boolean) => {
      if (!allowedSources.includes(source)) return;
      setPipelineSources((current) => {
        const next = checked
          ? Array.from(new Set([...current, source]))
          : current.filter((value) => value !== source);

        return next.length === 0 ? current : next;
      });
    },
    [allowedSources],
  );

  return { pipelineSources, setPipelineSources, toggleSource };
};
