'use client';

import { useState, useCallback, useEffect, useRef } from 'react';
import type { Topic, ProviderConfig, AuthUser, AppMode } from '@/types';
import { useAppState } from '@/hooks/useAppState';
import { useAI } from '@/hooks/useAI';
import { loadProviderConfig, saveProviderConfig, PROVIDER_MAP } from '@/lib/providers';
import { loadLocalSession, saveLocalSession, clearLocalSession } from '@/lib/localSession';
import { TOPICS } from '@/lib/topics';
import TopicSelector from './TopicSelector';
import EditorPane from './editor/EditorPane';
import LessonPane from './classroom/LessonPane';
import ChatPane from './chat/ChatPane';
import ProviderSettings from './ProviderSettings';
import AuthModal from './AuthModal';

export default function AppShell() {
  const [state, dispatch] = useAppState();
  const [providerConfig, setProviderConfig] = useState<ProviderConfig>(loadProviderConfig);
  const [showSettings, setShowSettings] = useState(false);

  const [authUser, setAuthUser] = useState<AuthUser | null>(null);
  const [showAuth, setShowAuth] = useState(false);
  const [savedIndicator, setSavedIndicator] = useState(false);
  const [splitPercent, setSplitPercent] = useState(50);
  const containerRef = useRef<HTMLDivElement>(null);
  const dbSaveRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  // Keep localStorage in sync whenever providerConfig changes
  useEffect(() => {
    saveProviderConfig(providerConfig);
  }, [providerConfig]);

  // Load persisted responseMode on mount
  useEffect(() => {
    if (typeof window === 'undefined') return;
    try {
      const raw = localStorage.getItem('professor_response_mode');
      if (raw) dispatch({ type: 'SET_RESPONSE_MODE', payload: JSON.parse(raw) });
    } catch { /* ignore */ }
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // Persist responseMode whenever it changes
  useEffect(() => {
    if (typeof window === 'undefined') return;
    localStorage.setItem('professor_response_mode', JSON.stringify(state.responseMode));
  }, [state.responseMode]);

  // Check auth status on mount
  useEffect(() => {
    fetch('/api/auth/me')
      .then((r) => r.json())
      .then((data) => {
        if (data.user) setAuthUser(data.user as AuthUser);
      })
      .catch(() => {});
  }, []);

  // Restore session from localStorage on mount (immediate, works without an account)
  useEffect(() => {
    const local = loadLocalSession();
    if (!local) return;
    const topic = TOPICS.find((t) => t.id === local.topicId);
    if (topic && local.task) {
      dispatch({
        type: 'RESTORE_SESSION',
        payload: {
          topic,
          task: local.task,
          code: local.code,
          messages: local.messages,
          executionResult: local.executionResult,
        },
      });
    }
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  // When user logs in, fetch their DB session and prefer it over the local one
  useEffect(() => {
    if (!authUser) return;
    fetch('/api/session')
      .then((r) => r.json())
      .then((data) => {
        if (!data.session) return;
        const { topicId, task, code, messages, executionResult } = data.session;
        const topic = TOPICS.find((t) => t.id === topicId);
        if (topic && task) {
          dispatch({
            type: 'RESTORE_SESSION',
            payload: { topic, task, code: code ?? '', messages: messages ?? [], executionResult },
          });
          // Sync DB session down to local so they're consistent
          saveLocalSession({ topicId, task, code: code ?? '', messages: messages ?? [], executionResult });
        }
      })
      .catch(() => {});
  }, [authUser, dispatch]);

  // Auto-save session whenever relevant state changes
  useEffect(() => {
    if (state.phase === 'selecting' || !state.topic || !state.task) return;

    const sessionData = {
      topicId: state.topic.id,
      task: state.task,
      code: state.code,
      messages: state.messages,
      executionResult: state.executionResult,
    };

    // Always save to localStorage immediately
    saveLocalSession(sessionData);

    // Flash "Saved" indicator
    if (savedTimerRef.current) clearTimeout(savedTimerRef.current);
    setSavedIndicator(true);
    savedTimerRef.current = setTimeout(() => setSavedIndicator(false), 1500);

    // Debounced DB sync when logged in
    if (authUser) {
      if (dbSaveRef.current) clearTimeout(dbSaveRef.current);
      dbSaveRef.current = setTimeout(() => {
        fetch('/api/session', {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(sessionData),
        }).catch(() => {});
      }, 1000);
    }
  }, [state.topic, state.task, state.code, state.messages, state.executionResult, authUser]);

  const { generateTask, reviewCode, sendMessage, generateLesson, sendClassroomMessage } = useAI(dispatch, providerConfig);

  const handleTopicSelect = useCallback(
    (topic: Topic) => {
      clearLocalSession();
      dispatch({ type: 'SELECT_TOPIC', payload: topic });
      generateTask(topic);
    },
    [dispatch, generateTask]
  );

  const handleSubmit = useCallback(() => {
    reviewCode(state);
  }, [reviewCode, state]);

  const handleSendMessage = useCallback(
    (text: string) => {
      sendMessage(state, text);
    },
    [sendMessage, state]
  );

  const handleSendClassroomMessage = useCallback(
    (text: string) => {
      sendClassroomMessage(state, text);
    },
    [sendClassroomMessage, state]
  );

  const handleSetAppMode = useCallback(
    (mode: AppMode) => {
      dispatch({ type: 'SET_APP_MODE', payload: mode });
      // Lazily generate the lesson the first time the user enters Classroom mode
      if (mode === 'classroom' && !state.lessonContent && !state.isStreaming && state.topic) {
        generateLesson(state.topic);
      }
    },
    [dispatch, state.lessonContent, state.isStreaming, state.topic, generateLesson]
  );

  const handleReset = useCallback(() => {
    dispatch({ type: 'RESET' });
    clearLocalSession();
    // Clear DB session if logged in
    if (authUser) {
      fetch('/api/session', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ topicId: null, task: null, code: null, messages: [], executionResult: null }),
      }).catch(() => {});
    }
  }, [dispatch, authUser]);

  const handleSaveProvider = useCallback((config: ProviderConfig) => {
    setProviderConfig(config);
  }, []);

  const handleAuthSuccess = useCallback((user: AuthUser) => {
    setAuthUser(user);
    setShowAuth(false);
  }, []);

  const handleLogout = useCallback(async () => {
    await fetch('/api/auth/logout', { method: 'POST' });
    setAuthUser(null);
    // Local session stays intact — user can continue without an account
  }, []);

  const handlePaneDragStart = useCallback((e: React.MouseEvent) => {
    e.preventDefault();
    const container = containerRef.current;
    if (!container) return;

    const onMove = (e: MouseEvent) => {
      const rect = container.getBoundingClientRect();
      const isHorizontal = rect.width >= 1024; // lg breakpoint
      const pct = isHorizontal
        ? ((e.clientX - rect.left) / rect.width) * 100
        : ((e.clientY - rect.top) / rect.height) * 100;
      setSplitPercent(Math.min(Math.max(pct, 20), 80));
    };

    const onUp = () => {
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
    };

    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
  }, []);

  const providerDef = PROVIDER_MAP[providerConfig.provider];

  if (state.phase === 'selecting') {
    return (
      <>
        <TopicSelector onSelect={handleTopicSelect} onOpenSettings={() => setShowSettings(true)} />
        {showSettings && (
          <ProviderSettings
            config={providerConfig}
            onSave={handleSaveProvider}
            onClose={() => setShowSettings(false)}
          />
        )}
        {showAuth && (
          <AuthModal onSuccess={handleAuthSuccess} onClose={() => setShowAuth(false)} />
        )}
      </>
    );
  }

  return (
    <>
      <div ref={containerRef} className="flex h-screen w-full overflow-hidden bg-zinc-950 flex-col lg:flex-row">
        {/* Left pane — editor (Homework) or lesson viewer (Classroom) */}
        <div
          className="flex flex-col min-h-0 min-w-0 overflow-hidden"
          style={{ flex: `0 0 ${splitPercent}%` }}
        >
          {state.appMode === 'classroom' ? (
            <LessonPane
              topic={state.topic!}
              lessonContent={state.lessonContent}
              isGenerating={state.isStreaming && state.lessonContent === null}
              streamingContent={state.streamingContent}
            />
          ) : (
            <EditorPane
              state={state}
              dispatch={dispatch}
              providerLabel={`${providerDef.label} · ${providerConfig.model}`}
              onSubmit={handleSubmit}
              onReset={handleReset}
              onOpenSettings={() => setShowSettings(true)}
              savedIndicator={savedIndicator}
              authUser={authUser}
              onShowAuth={() => setShowAuth(true)}
              onLogout={handleLogout}
            />
          )}
        </div>

        {/* Drag handle */}
        <div
          onMouseDown={handlePaneDragStart}
          className="group relative flex-shrink-0 select-none
            h-1 w-full cursor-row-resize
            lg:h-full lg:w-1 lg:cursor-col-resize
            bg-zinc-700 hover:bg-blue-500 active:bg-blue-400 transition-colors duration-100"
        />

        {/* Right pane — chat */}
        <div className="flex flex-col flex-1 min-h-0 min-w-0 overflow-hidden">
          <ChatPane
            state={state}
            dispatch={dispatch}
            onSendMessage={handleSendMessage}
            onSendClassroomMessage={handleSendClassroomMessage}
            onSubmit={handleSubmit}
            onSetAppMode={handleSetAppMode}
          />
        </div>
      </div>

      {showSettings && (
        <ProviderSettings
          config={providerConfig}
          onSave={handleSaveProvider}
          onClose={() => setShowSettings(false)}
        />
      )}

      {showAuth && (
        <AuthModal onSuccess={handleAuthSuccess} onClose={() => setShowAuth(false)} />
      )}
    </>
  );
}
