import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { motion } from 'framer-motion';
import { api } from '../../shared/lib/apiClient';
import { unwrapArray, unwrapObject } from '../../shared/lib/apiShape';
import { OracleResultCard } from './OracleResultCard';
import styles from './OracleChatConsole.module.css';

type OracleRow = Record<string, unknown>;

interface OracleResult {
  title?: string;
  summary?: string;
  columns?: string[];
  rows?: OracleRow[];
  rowCount?: number;
  componentType?: string;
  warnings?: string[];
  sourceTables?: string[];
}

interface OracleTurn {
  id: string;
  prompt: string;
  createdAt: string;
  status: 'thinking' | 'done' | 'failed';
  result?: OracleResult;
  error?: string;
}

interface OracleSession {
  id: string;
  title: string;
  createdAt: string;
  updatedAt: string;
  turns: OracleTurn[];
}

const STORAGE_KEY = 'velocity-oracle-chat-sessions-v1';

function makeId(prefix: string) {
  return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}

function createSession(title = 'New Oracle Chat'): OracleSession {
  const now = new Date().toISOString();
  return {
    id: makeId('oracle'),
    title,
    createdAt: now,
    updatedAt: now,
    turns: [],
  };
}

function deriveTitle(prompt: string) {
  const clean = prompt.trim().replace(/\s+/g, ' ');
  return clean.length > 58 ? `${clean.slice(0, 55)}...` : clean || 'Oracle Chat';
}

function normalizeResult(raw: unknown, prompt: string): OracleResult {
  const body = unwrapObject<Record<string, unknown>>(raw) ?? {};
  const data = unwrapObject<Record<string, unknown>>(body.data ?? body.result ?? body.payload ?? body) ?? {};
  const components = unwrapArray<Record<string, unknown>>(data.components ?? data.componentPlan ?? data.canvasComponents);
  const firstComponent = unwrapObject<Record<string, unknown>>(components[0]) ?? {};
  const rows = unwrapArray<OracleRow>(data.rows ?? data.dataRows ?? firstComponent.dataRows ?? firstComponent.rows);
  const columns = unwrapArray<unknown>(data.columns ?? firstComponent.columns);
  const sourceTables = unwrapArray<unknown>(data.sourceTables ?? data.source_tables ?? firstComponent.sourceTables);
  const warnings = unwrapArray<unknown>(data.warnings ?? firstComponent.warnings);

  return {
    title: String(data.title ?? firstComponent.title ?? `Oracle result for "${prompt}"`),
    summary: String(data.summary ?? firstComponent.summary ?? data.sqlSummary ?? ''),
    rows,
    columns: columns.length ? columns.map(String) : rows[0] ? Object.keys(rows[0]) : [],
    rowCount: Number(data.rowCount ?? data.row_count ?? rows.length),
    componentType: String(data.componentType ?? data.component_type ?? firstComponent.type ?? firstComponent.componentType ?? 'table'),
    warnings: warnings.map(String),
    sourceTables: sourceTables.map(String),
  };
}

function deriveRowLimit(prompt: string) {
  const numeric = prompt.match(/\b(?:top|last|first|lowest|highest)?\s*(\d{1,3})\b/i);
  if (numeric) return Math.min(Math.max(Number(numeric[1]), 1), 100);
  const words: Record<string, number> = {
    one: 1,
    two: 2,
    three: 3,
    four: 4,
    five: 5,
    six: 6,
    seven: 7,
    eight: 8,
    nine: 9,
    ten: 10,
  };
  const word = prompt.toLowerCase().match(/\b(one|two|three|four|five|six|seven|eight|nine|ten)\b/);
  return word ? words[word[1]] : 10;
}

function relativeTime(value: string) {
  const delta = Date.now() - new Date(value).getTime();
  const minutes = Math.max(1, Math.floor(delta / 60000));
  if (minutes < 60) return `${minutes}m ago`;
  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `${hours}h ago`;
  return `${Math.floor(hours / 24)}d ago`;
}

function loadSessions(): OracleSession[] {
  try {
    const parsed = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]');
    return Array.isArray(parsed) && parsed.length ? parsed : [createSession('Oracle Main Canvas')];
  } catch {
    return [createSession('Oracle Main Canvas')];
  }
}

export default function OracleChatConsole() {
  const [sessions, setSessions] = useState<OracleSession[]>(loadSessions);
  const [activeId, setActiveId] = useState(() => sessions[0]?.id ?? '');
  const [prompt, setPrompt] = useState('');
  const [search, setSearch] = useState('');
  const [shareNote, setShareNote] = useState('');
  const inputRef = useRef<HTMLTextAreaElement | null>(null);

  const activeSession = useMemo(
    () => sessions.find((session) => session.id === activeId) ?? sessions[0],
    [activeId, sessions],
  );

  const filteredSessions = useMemo(() => {
    const term = search.trim().toLowerCase();
    const sorted = [...sessions].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
    if (!term) return sorted;
    return sorted.filter((session) =>
      session.title.toLowerCase().includes(term)
      || session.turns.some((turn) => turn.prompt.toLowerCase().includes(term)),
    );
  }, [search, sessions]);

  useEffect(() => {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions.slice(0, 30)));
  }, [sessions]);

  const startNewChat = useCallback(() => {
    const session = createSession();
    setSessions((current) => [session, ...current]);
    setActiveId(session.id);
    setPrompt('');
    setTimeout(() => inputRef.current?.focus(), 50);
  }, []);

  const submitPrompt = useCallback(async () => {
    const clean = prompt.trim();
    if (!clean || !activeSession) return;

    const turnId = makeId('turn');
    const now = new Date().toISOString();
    setPrompt('');
    setShareNote('');

    setSessions((current) => current.map((session) => {
      if (session.id !== activeSession.id) return session;
      const title = session.turns.length === 0 && session.title === 'New Oracle Chat'
        ? deriveTitle(clean)
        : session.title;
      return {
        ...session,
        title,
        updatedAt: now,
        turns: [
          ...session.turns,
          { id: turnId, prompt: clean, createdAt: now, status: 'thinking' },
        ],
      };
    }));

    try {
      const response = await api.post('/oracle/query', {
        prompt: clean,
        row_limit: deriveRowLimit(clean),
        context: {
          surface: 'velocity_os_oracle_chat',
          session_id: activeSession.id,
        },
      });
      const result = normalizeResult(response, clean);
      setSessions((current) => current.map((session) => {
        if (session.id !== activeSession.id) return session;
        return {
          ...session,
          updatedAt: new Date().toISOString(),
          turns: session.turns.map((turn) => (
            turn.id === turnId ? { ...turn, status: 'done', result } : turn
          )),
        };
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Oracle request failed';
      setSessions((current) => current.map((session) => {
        if (session.id !== activeSession.id) return session;
        return {
          ...session,
          updatedAt: new Date().toISOString(),
          turns: session.turns.map((turn) => (
            turn.id === turnId ? { ...turn, status: 'failed', error: message } : turn
          )),
        };
      }));
    }
  }, [activeSession, prompt]);

  const shareSession = useCallback(async () => {
    if (!activeSession) return;
    const payload = JSON.stringify(activeSession, null, 2);
    try {
      await navigator.clipboard.writeText(payload);
      setShareNote('Chat copied for sharing');
    } catch {
      setShareNote('Share export prepared in browser memory');
    }
  }, [activeSession]);

  return (
    <section className={styles.shell} aria-label="Oracle chat canvas">
      <aside className={styles.rail}>
        <div>
          <p className={styles.eyebrow}>Oracle Canvas</p>
          <h2 className={styles.title}>Ask, save, share</h2>
          <p className={styles.caption}>Every search becomes a chat tab with persistent visual results.</p>
        </div>

        <button className={`${styles.railButton} ${styles.primaryButton}`} type="button" onClick={startNewChat}>
          + New Chat
        </button>
        <input
          className={styles.searchInput}
          value={search}
          onChange={(event) => setSearch(event.target.value)}
          placeholder="Search chats..."
        />

        <p className={styles.sectionLabel}>Recent</p>
        <div className={styles.sessions}>
          {filteredSessions.map((session) => (
            <button
              key={session.id}
              type="button"
              className={`${styles.sessionButton} ${session.id === activeSession?.id ? styles.sessionActive : ''}`}
              onClick={() => setActiveId(session.id)}
            >
              <span className={styles.sessionGlyph}>{session.title.slice(0, 1).toUpperCase()}</span>
              <span className={styles.sessionMeta}>
                <span className={styles.sessionTitle}>{session.title}</span>
                <span className={styles.sessionSub}>{session.turns.length} prompts · {relativeTime(session.updatedAt)}</span>
              </span>
            </button>
          ))}
          {!filteredSessions.length && <div className={styles.emptySessions}>No matching chats.</div>}
        </div>
      </aside>

      <main className={styles.main}>
        <div className={styles.topbar}>
          <div>
            <h1 className={styles.topbarTitle}>{activeSession?.title ?? 'Oracle Canvas'}</h1>
            <p className={styles.topbarSub}>Natural CRM intelligence over live Velocity data</p>
          </div>
          <div>
            <button className={styles.shareButton} type="button" onClick={shareSession}>Share / Export</button>
            {shareNote && <p className={styles.notice}>{shareNote}</p>}
          </div>
        </div>

        <div className={styles.thread}>
          {!activeSession?.turns.length && (
            <div className={styles.emptyCanvas}>
              <div className={styles.emptyIcon}>✦</div>
              <h3>Start with a business question</h3>
              <p>Example: “Which clients have not been contacted in 7 days but have high QD?”</p>
            </div>
          )}

          {activeSession?.turns.map((turn) => (
            <motion.article
              key={turn.id}
              className={styles.turn}
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
            >
              <div className={styles.userBubble}>{turn.prompt}</div>
              {turn.status === 'thinking' && <div className={`${styles.thinkingCard} glass-card skeleton-shimmer`} />}
              {turn.status === 'failed' && (
                <OracleResultCard
                  query={turn.prompt}
                  result={{
                    title: 'Oracle request failed',
                    summary: turn.error,
                    rows: [],
                    warnings: turn.error ? [turn.error] : [],
                  }}
                />
              )}
              {turn.status === 'done' && turn.result && (
                <OracleResultCard result={turn.result} query={turn.prompt} />
              )}
            </motion.article>
          ))}
        </div>

        <form
          className={styles.composer}
          onSubmit={(event) => {
            event.preventDefault();
            void submitPrompt();
          }}
        >
          <div className={styles.composerInner}>
            <textarea
              ref={inputRef}
              className={styles.composerInput}
              value={prompt}
              onChange={(event) => setPrompt(event.target.value)}
              onKeyDown={(event) => {
                if (event.key === 'Enter' && !event.shiftKey) {
                  event.preventDefault();
                  void submitPrompt();
                }
              }}
              placeholder="Ask Oracle anything about clients, properties, QD, calls, visits, campaigns..."
            />
            <button className={styles.sendButton} type="submit" disabled={!prompt.trim()}>
              →
            </button>
          </div>
        </form>
      </main>
    </section>
  );
}
