import { useCallback, useEffect, useState } from 'react';
import { ChatHistoryEntry, TerminalEntry } from '../types/terminal';

const STORAGE_KEY = 'chat_history';
const MAX_CHAT_HISTORY = 10;

const stripEmptyTrailingEntries = (entries: TerminalEntry[]): TerminalEntry[] => {
  let end = entries.length;
  while (end > 0) {
    const entry = entries[end - 1];
    if (
      (entry.type === 'response' || entry.type === 'thinking') &&
      (typeof entry.content !== 'string' || entry.content.trim() === '')
    ) {
      end--;
    } else {
      break;
    }
  }
  return entries.slice(0, end);
};

const hasMeaningfulContent = (entries: TerminalEntry[]): boolean => {
  const hasCommand = entries.some(
    (e) => e.type === 'command' && typeof e.content === 'string',
  );
  if (!hasCommand) return false;

  return entries.some((e) => {
    if (e.type === 'response' && typeof e.content === 'string' && e.content.trim()) {
      return true;
    }
    if (e.type === 'panel') return true;
    if (e.type === 'error' && typeof e.content === 'string' && e.content.trim()) {
      return true;
    }
    return false;
  });
};

const countCommands = (entries: TerminalEntry[]): number =>
  entries.filter(
    (e) => e.type === 'command' && typeof e.content === 'string' && e.content.startsWith('/'),
  ).length;

const extractTitle = (prompt: string): string => {
  const firstLine = prompt.split('\n')[0].trim();
  return firstLine.length > 48 ? firstLine.slice(0, 48) : firstLine;
};

const extractResponsePreview = (entries: TerminalEntry[]): string | undefined => {
  for (const entry of entries) {
    if (
      entry.type === 'response' &&
      typeof entry.content === 'string' &&
      entry.content.trim()
    ) {
      const stripped = entry.content.trim();
      return stripped.length > 96 ? stripped.slice(0, 96) : stripped;
    }
  }
  return undefined;
};

export const buildChatHistoryEntry = (
  prompt: string,
  transcript: TerminalEntry[],
): ChatHistoryEntry | null => {
  const cleaned = stripEmptyTrailingEntries(transcript);
  if (!hasMeaningfulContent(cleaned)) return null;

  const now = new Date();
  return {
    id: `chat-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
    title: extractTitle(prompt),
    prompt,
    transcript: cleaned,
    createdAt: now,
    updatedAt: now,
    commandCount: countCommands(cleaned),
    responsePreview: extractResponsePreview(cleaned),
  };
};

const deserializeTimestamp = (value: unknown): Date => {
  if (typeof value === 'string') {
    const d = new Date(value);
    if (!Number.isNaN(d.getTime())) return d;
  }
  return new Date();
};

const deserializeEntry = (entry: TerminalEntry): TerminalEntry => ({
  ...entry,
  timestamp: entry.timestamp ? deserializeTimestamp(entry.timestamp) : new Date(),
});

const deserializeChatHistoryEntry = (raw: Record<string, unknown>): ChatHistoryEntry | null => {
  try {
    if (
      typeof raw.id !== 'string' ||
      typeof raw.title !== 'string' ||
      typeof raw.prompt !== 'string' ||
      !Array.isArray(raw.transcript)
    ) {
      return null;
    }

    const transcript = (raw.transcript as TerminalEntry[]).map(deserializeEntry);

    return {
      id: raw.id,
      title: raw.title,
      prompt: raw.prompt,
      transcript,
      createdAt: deserializeTimestamp(raw.createdAt),
      updatedAt: deserializeTimestamp(raw.updatedAt),
      commandCount: typeof raw.commandCount === 'number' ? raw.commandCount : 0,
      responsePreview: typeof raw.responsePreview === 'string' ? raw.responsePreview : undefined,
    };
  } catch {
    return null;
  }
};

export const useChatHistory = () => {
  const [history, setHistory] = useState<ChatHistoryEntry[]>([]);
  const [isLoaded, setIsLoaded] = useState(false);

  useEffect(() => {
    try {
      const stored = localStorage.getItem(STORAGE_KEY);
      if (stored) {
        const parsed = JSON.parse(stored);
        if (Array.isArray(parsed)) {
          const loaded = parsed
            .map((item: unknown) =>
              deserializeChatHistoryEntry(item as Record<string, unknown>),
            )
            .filter((e: ChatHistoryEntry | null): e is ChatHistoryEntry => e !== null)
            .slice(0, MAX_CHAT_HISTORY);
          setHistory(loaded);
        }
      }
    } catch (error) {
      console.error('Failed to load chat history from localStorage:', error);
    } finally {
      setIsLoaded(true);
    }
  }, []);

  useEffect(() => {
    if (!isLoaded) return;

    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(history));
    } catch (error) {
      console.error('Failed to save chat history to localStorage:', error);
    }
  }, [history, isLoaded]);

  const recordChat = useCallback(
    (entry: { prompt: string; transcript: TerminalEntry[]; completedAt?: Date }) => {
      const chatEntry = buildChatHistoryEntry(entry.prompt, entry.transcript);
      if (!chatEntry) return;

      if (entry.completedAt) {
        chatEntry.updatedAt = entry.completedAt;
      }

      setHistory((prev) => {
        const deduped = prev.filter((e) => e.id !== chatEntry.id && e.prompt !== entry.prompt);
        return [chatEntry, ...deduped].slice(0, MAX_CHAT_HISTORY);
      });
    },
    [],
  );

  const clearHistory = useCallback(() => {
    setHistory([]);
  }, []);

  const removeChat = useCallback((id: string) => {
    setHistory((prev) => prev.filter((e) => e.id !== id));
  }, []);

  return {
    history,
    isLoaded,
    recordChat,
    clearHistory,
    removeChat,
  };
};
