import { useState, useEffect, useCallback, useMemo } from 'react';
import sfdaEntriesService, {
  type SfdaDeviceEntry,
  type SfdaEntry,
  type SfdaEntryListParams,
} from '../services/sfdaEntriesService';
import assetService from '../services/assetService';

interface UseSfdaEntryListResult {
  entries: SfdaEntry[];
  loading: boolean;
  error: string | null;
  totalCount: number;
  refetch: () => void;
}

interface UseSfdaEntryDetailsResult {
  entry: SfdaEntry | null;
  loading: boolean;
  error: string | null;
  refetch: () => void;
}

export function useSfdaEntryList(params: SfdaEntryListParams = {}): UseSfdaEntryListResult {
  const [entries, setEntries] = useState<SfdaEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [totalCount, setTotalCount] = useState(0);

  const paramsKey = JSON.stringify(params);

  const fetchData = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);
      const [listResponse, count] = await Promise.all([
        sfdaEntriesService.getEntries(params),
        sfdaEntriesService.getEntryCount(params.filters || {}),
      ]);
      setEntries(listResponse.data);
      setTotalCount(count);
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Failed to fetch SFDA entries';
      setError(errorMessage);
      console.error('Error fetching SFDA entries:', err);
    } finally {
      setLoading(false);
    }
  }, [paramsKey]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  return {
    entries,
    loading,
    error,
    totalCount,
    refetch: fetchData,
  };
}

export function useSfdaEntryDetails(name: string | null): UseSfdaEntryDetailsResult {
  const [entry, setEntry] = useState<SfdaEntry | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const fetchEntry = useCallback(async () => {
    if (!name) {
      setLoading(false);
      return;
    }

    try {
      setLoading(true);
      setError(null);
      const data = await sfdaEntriesService.getEntry(name);
      setEntry(data);
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Failed to fetch SFDA entry';
      setError(errorMessage);
      console.error('Error fetching SFDA entry:', err);
    } finally {
      setLoading(false);
    }
  }, [name]);

  useEffect(() => {
    fetchEntry();
  }, [fetchEntry]);

  return {
    entry,
    loading,
    error,
    refetch: fetchEntry,
  };
}

function matchingRank(value?: string): number {
  const normalized = (value || '').trim().toLowerCase();
  if (normalized === 'yes') return 0;
  if (normalized === 'no') return 1;
  return 2;
}

function isMatchingYes(value?: string): boolean {
  return (value || '').trim().toLowerCase() === 'yes';
}

function collectYesRowLookupValues(rows: SfdaDeviceEntry[]): string[] {
  const values = new Set<string>();
  for (const row of rows) {
    if (!isMatchingYes(row.serial_no_matching)) {
      continue;
    }
    for (const field of ['serial_no', 'catalog_number'] as const) {
      const raw = row[field];
      if (!raw) {
        continue;
      }
      for (const part of raw.split(',')) {
        const trimmed = part.trim();
        if (trimmed) {
          values.add(trimmed);
        }
      }
    }
  }
  return Array.from(values);
}

function sortDeviceListByMatching(rows: SfdaDeviceEntry[]): SfdaDeviceEntry[] {
  return [...rows].sort((a, b) => {
    const rankDiff = matchingRank(a.serial_no_matching) - matchingRank(b.serial_no_matching);
    if (rankDiff !== 0) {
      return rankDiff;
    }
    return (a.idx ?? 0) - (b.idx ?? 0);
  });
}

interface UseSfdaAssetMatchesResult {
  sortedDeviceList: SfdaDeviceEntry[];
  matchedSerialNumbers: Set<string>;
  matchesLoading: boolean;
}

export function useSfdaAssetMatches(
  deviceList: SfdaDeviceEntry[] | undefined
): UseSfdaAssetMatchesResult {
  const rows = deviceList || [];
  const sortedDeviceList = useMemo(() => sortDeviceListByMatching(rows), [rows]);
  const lookupValues = useMemo(() => collectYesRowLookupValues(rows), [rows]);
  const lookupKey = lookupValues.join('\0');

  const [matchedSerialNumbers, setMatchedSerialNumbers] = useState<Set<string>>(new Set());
  const [matchesLoading, setMatchesLoading] = useState(false);

  useEffect(() => {
    if (lookupValues.length === 0) {
      setMatchedSerialNumbers(new Set());
      setMatchesLoading(false);
      return;
    }

    let cancelled = false;
    setMatchesLoading(true);

    assetService
      .getExistingSerialNumbers(lookupValues)
      .then((matched) => {
        if (!cancelled) {
          setMatchedSerialNumbers(matched);
        }
      })
      .catch((err) => {
        console.error('Error resolving SFDA asset matches:', err);
        if (!cancelled) {
          setMatchedSerialNumbers(new Set());
        }
      })
      .finally(() => {
        if (!cancelled) {
          setMatchesLoading(false);
        }
      });

    return () => {
      cancelled = true;
    };
  }, [lookupKey]);

  return {
    sortedDeviceList,
    matchedSerialNumbers,
    matchesLoading,
  };
}
