import React, { useState, useEffect, useMemo } from 'react';
import { Header } from './components/Header';
import { LeftSidebar } from './components/LeftSidebar';
import { ChatArea } from './components/ChatArea';
import { RightPanel } from './components/RightPanel';
import { FloatingActionButtons } from './components/FloatingActionButtons';
import { X, ChevronLeft, ChevronRight } from 'lucide-react';
import { Button } from './components/ui/button';
import { Toaster } from './components/ui/sonner';
import { toast } from 'sonner';

export interface Message {
  id: string;
  role: 'user' | 'assistant';
  content: string;
  timestamp: Date;
  references?: string[];
  sender?: GroupMember; // For group chat
}

export interface User {
  name: string;
  email: string;
}

export interface GroupMember {
  id: string;
  name: string;
  email: string;
  avatar?: string;
  isAI?: boolean;
}

export type SpaceType = 'individual' | 'group';

export type FileType = 'syllabus' | 'lecture-slides' | 'literature-review' | 'other';

export interface UploadedFile {
  file: File;
  type: FileType;
  uploaded?: boolean;
  uploadedChunks?: number;
}

export type LearningMode = 'concept' | 'socratic' | 'exam' | 'assignment' | 'summary';
export type Language = 'auto' | 'en' | 'zh';

type ChatApiResp = {
  reply: string;
  session_status_md?: string;
  refs?: Array<{ source_file?: string; section?: string }>;
  latency_ms?: number;
};

type UploadApiResp = {
  ok: boolean;
  added_chunks: number;
  status_md: string;
};

function mapFileTypeToDocType(t: FileType): string {
  switch (t) {
    case 'syllabus':
      return 'Syllabus';
    case 'lecture-slides':
      return 'Lecture Slides';
    case 'literature-review':
      return 'Literature Review / Paper';
    default:
      return 'Other';
  }
}

async function apiPostJson<T>(path: string, payload: any): Promise<T> {
  const res = await fetch(path, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  if (!res.ok) {
    const txt = await res.text().catch(() => '');
    throw new Error(`HTTP ${res.status}: ${txt || res.statusText}`);
  }
  return (await res.json()) as T;
}

async function apiPostForm<T>(path: string, form: FormData): Promise<T> {
  const res = await fetch(path, { method: 'POST', body: form });
  if (!res.ok) {
    const txt = await res.text().catch(() => '');
    throw new Error(`HTTP ${res.status}: ${txt || res.statusText}`);
  }
  return (await res.json()) as T;
}

function App() {
  const [isDarkMode, setIsDarkMode] = useState(() => {
    const saved = localStorage.getItem('theme');
    return saved === 'dark' || (!saved && window.matchMedia('(prefers-color-scheme: dark)').matches);
  });

  const [user, setUser] = useState<User | null>(null);

  const [messages, setMessages] = useState<Message[]>([
    {
      id: '1',
      role: 'assistant',
      content:
        "Hi! I'm Clare, your AI teaching assistant for Module 10 – Responsible AI. Upload your materials (e.g., syllabus/lecture slides) and ask me anything.",
      timestamp: new Date(),
    },
  ]);

  const [learningMode, setLearningMode] = useState<LearningMode>('concept');
  const [language, setLanguage] = useState<Language>('auto');

  const [uploadedFiles, setUploadedFiles] = useState<UploadedFile[]>([]);
  const [memoryProgress, setMemoryProgress] = useState(40);

  const [leftSidebarOpen, setLeftSidebarOpen] = useState(false);
  const [rightPanelOpen, setRightPanelOpen] = useState(false);
  const [rightPanelVisible, setRightPanelVisible] = useState(true);

  const [spaceType, setSpaceType] = useState<SpaceType>('individual');

  const [exportResult, setExportResult] = useState('');
  const [resultType, setResultType] = useState<'export' | 'quiz' | 'summary' | null>(null);

  const [groupMembers] = useState<GroupMember[]>([
    { id: 'clare', name: 'Clare AI', email: 'clare@ai.assistant', isAI: true },
    { id: '1', name: 'Sarah Johnson', email: 'sarah.j@university.edu' },
    { id: '2', name: 'Michael Chen', email: 'michael.c@university.edu' },
    { id: '3', name: 'Emma Williams', email: 'emma.w@university.edu' },
  ]);

  useEffect(() => {
    document.documentElement.classList.toggle('dark', isDarkMode);
    localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
  }, [isDarkMode]);

  const userId = useMemo(() => {
    // 登录时：email 作为 user_id；不登录也可跑通：0405
    return (user?.email || '0405').trim();
  }, [user]);

  const isLoggedIn = useMemo(() => {
    // 你如果希望“必须登录才能聊天/上传”，这里改回 !!user
    // 目前为了便于调试后端，允许未登录也走通（user_id=0405）
    return true;
  }, []);

  const currentDocTypeForChat = useMemo(() => {
    const hasSyllabus = uploadedFiles.some((f) => f.type === 'syllabus' && f.uploaded);
    if (hasSyllabus) return 'Syllabus';
    const hasSlides = uploadedFiles.some((f) => f.type === 'lecture-slides' && f.uploaded);
    if (hasSlides) return 'Lecture Slides';
    const hasLit = uploadedFiles.some((f) => f.type === 'literature-review' && f.uploaded);
    if (hasLit) return 'Literature Review / Paper';
    return 'Other';
  }, [uploadedFiles]);

  const handleSendMessage = async (content: string) => {
    if (!content.trim()) return;

    const shouldAIRespond = spaceType === 'individual' || content.toLowerCase().includes('@clare');

    const sender: GroupMember | undefined =
      spaceType === 'group' && user
        ? { id: user.email, name: user.name, email: user.email }
        : undefined;

    const userMessage: Message = {
      id: Date.now().toString(),
      role: 'user',
      content,
      timestamp: new Date(),
      sender,
    };
    setMessages((prev) => [...prev, userMessage]);

    if (!shouldAIRespond) return;

    try {
      const resp = await apiPostJson<ChatApiResp>('/api/chat', {
        user_id: userId,
        message: content,
        learning_mode: learningMode,
        language_preference: language === 'auto' ? 'Auto' : language,
        doc_type: currentDocTypeForChat,
      });

      const refs = (resp.refs || [])
        .map((r) => [r.source_file, r.section].filter(Boolean).join(' / '))
        .filter(Boolean);

      const assistantMessage: Message = {
        id: (Date.now() + 1).toString(),
        role: 'assistant',
        content: resp.reply || '(empty reply)',
        timestamp: new Date(),
        references: refs.length ? refs : undefined,
        sender: spaceType === 'group' ? groupMembers.find((m) => m.isAI) : undefined,
      };

      setMessages((prev) => [...prev, assistantMessage]);
    } catch (e: any) {
      console.error(e);
      toast.error(`Chat failed: ${e?.message || 'unknown error'}`);
      setMessages((prev) => [
        ...prev,
        {
          id: (Date.now() + 1).toString(),
          role: 'assistant',
          content: `Sorry — chat request failed. ${e?.message || ''}`,
          timestamp: new Date(),
        },
      ]);
    }
  };

  // ✅ 选文件：只入库，不上传
  const handleFileUpload = (files: File[]) => {
    const newFiles: UploadedFile[] = files.map((file) => ({
      file,
      type: 'other',
      uploaded: false,
    }));
    setUploadedFiles((prev) => [...prev, ...newFiles]);
    toast.message('Files added. Select a File Type, then click Upload.');
  };

  const handleRemoveFile = (index: number) => {
    setUploadedFiles((prev) => prev.filter((_, i) => i !== index));
  };

  const handleFileTypeChange = (index: number, type: FileType) => {
    setUploadedFiles((prev) => prev.map((f, i) => (i === index ? { ...f, type } : f)));
  };

  // ✅ 上传单个文件（关键：读取“最新的 type”，写入 doc_type）
  const handleUploadSingle = async (index: number) => {
    const target = uploadedFiles[index];
    if (!target) return;

    try {
      const form = new FormData();
      form.append('user_id', userId);
      form.append('doc_type', mapFileTypeToDocType(target.type));
      form.append('file', target.file);

      const r = await apiPostForm<UploadApiResp>('/api/upload', form);
      if (!r.ok) throw new Error('Upload response ok=false');

      setUploadedFiles((prev) =>
        prev.map((x, i) =>
          i === index ? { ...x, uploaded: true, uploadedChunks: r.added_chunks } : x
        )
      );

      toast.success(`Uploaded: ${target.file.name} (+${r.added_chunks} chunks)`);
    } catch (e: any) {
      console.error(e);
      toast.error(`Upload failed: ${e?.message || 'unknown error'}`);
    }
  };

  // ✅ 上传所有未上传
  const handleUploadAllPending = async () => {
    const pendingIdx = uploadedFiles
      .map((f, i) => ({ f, i }))
      .filter((x) => !x.f.uploaded)
      .map((x) => x.i);

    if (!pendingIdx.length) {
      toast.message('No pending files to upload.');
      return;
    }

    for (const idx of pendingIdx) {
      // 顺序上传便于 debug
      // eslint-disable-next-line no-await-in-loop
      await handleUploadSingle(idx);
    }
  };

  const handleClearConversation = () => {
    setMessages([
      {
        id: '1',
        role: 'assistant',
        content:
          "Hi! I'm Clare, your AI teaching assistant for Module 10 – Responsible AI. Upload your materials (e.g., syllabus/lecture slides) and ask me anything.",
        timestamp: new Date(),
      },
    ]);
  };

  const handleExport = async () => {
    try {
      const r = await apiPostJson<{ markdown: string }>('/api/export', {
        user_id: userId,
        learning_mode: learningMode,
      });
      setExportResult(r.markdown || '');
      setResultType('export');
      toast.success('Conversation exported!');
    } catch (e: any) {
      toast.error(`Export failed: ${e?.message || 'unknown error'}`);
    }
  };

  const handleSummary = async () => {
    try {
      const r = await apiPostJson<{ markdown: string }>('/api/summary', {
        user_id: userId,
        learning_mode: learningMode,
        language_preference: language === 'auto' ? 'Auto' : language,
      });
      setExportResult(r.markdown || '');
      setResultType('summary');
      toast.success('Summary generated!');
    } catch (e: any) {
      toast.error(`Summary failed: ${e?.message || 'unknown error'}`);
    }
  };

  const handleQuiz = () => {
    const quiz = `# Micro-Quiz: Responsible AI

1) Which is a key principle of Responsible AI?
A) Profit maximization
B) Transparency
C) Rapid deployment
D) Cost reduction
`;
    setExportResult(quiz);
    setResultType('quiz');
    toast.success('Quiz generated!');
  };

  useEffect(() => {
    const run = async () => {
      try {
        const res = await fetch(`/api/memoryline?user_id=${encodeURIComponent(userId)}`);
        if (!res.ok) return;
        const j = await res.json();
        const pct = typeof j?.progress_pct === 'number' ? j.progress_pct : null;
        if (pct !== null) setMemoryProgress(Math.round(pct * 100));
      } catch {
        // ignore
      }
    };
    run();
  }, [userId]);

  return (
    <div className="min-h-screen bg-background flex flex-col">
      <Toaster />
      <Header
        user={user}
        onMenuClick={() => setLeftSidebarOpen(!leftSidebarOpen)}
        onUserClick={() => setRightPanelOpen(!rightPanelOpen)}
        isDarkMode={isDarkMode}
        onToggleDarkMode={() => setIsDarkMode(!isDarkMode)}
      />

      <div className="flex-1 flex overflow-hidden">
        {leftSidebarOpen && (
          <div className="fixed inset-0 bg-black/50 z-40 lg:hidden" onClick={() => setLeftSidebarOpen(false)} />
        )}

        <aside
          className={`
            fixed lg:static inset-y-0 left-0 z-50
            w-80 bg-card border-r border-border
            transform transition-transform duration-300 ease-in-out
            ${leftSidebarOpen ? 'translate-x-0' : '-translate-x-full'}
            lg:translate-x-0
            flex flex-col
            mt-16 lg:mt-0
          `}
        >
          <div className="lg:hidden p-4 border-b border-border flex justify-between items-center">
            <h3>Settings & Guide</h3>
            <Button variant="ghost" size="icon" onClick={() => setLeftSidebarOpen(false)}>
              <X className="h-5 w-5" />
            </Button>
          </div>

          <LeftSidebar
            learningMode={learningMode}
            language={language}
            onLearningModeChange={setLearningMode}
            onLanguageChange={setLanguage}
            spaceType={spaceType}
            onSpaceTypeChange={setSpaceType}
            groupMembers={groupMembers}
          />
        </aside>

        <main className="flex-1 flex flex-col min-w-0">
          <ChatArea
            userId={userId}
            messages={messages}
            onSendMessage={handleSendMessage}
            uploadedFiles={uploadedFiles}
            onFileUpload={handleFileUpload}
            onRemoveFile={handleRemoveFile}
            onFileTypeChange={handleFileTypeChange}
            onUploadFile={handleUploadSingle}
            onUploadAll={handleUploadAllPending}
            memoryProgress={memoryProgress}
            isLoggedIn={isLoggedIn}
            learningMode={learningMode}
            onClearConversation={handleClearConversation}
            onLearningModeChange={setLearningMode}
            spaceType={spaceType}
          />
        </main>

        {rightPanelOpen && (
          <div className="fixed inset-0 bg-black/50 z-40 lg:hidden" onClick={() => setRightPanelOpen(false)} />
        )}

        {rightPanelVisible && (
          <aside
            className={`
              fixed lg:static inset-y-0 right-0 z-50
              w-80 bg-card border-l border-border
              transform transition-transform duration-300 ease-in-out
              ${rightPanelOpen ? 'translate-x-0' : 'translate-x-full'}
              lg:translate-x-0
              flex flex-col
              mt-16 lg:mt-0
            `}
          >
            <div className="lg:hidden p-4 border-b border-border flex justify-between items-center">
              <h3>Account & Actions</h3>
              <Button variant="ghost" size="icon" onClick={() => setRightPanelOpen(false)}>
                <X className="h-5 w-5" />
              </Button>
            </div>

            <RightPanel
              user={user}
              onLogin={setUser}
              onLogout={() => setUser(null)}
              isLoggedIn={!!user}
              onClose={() => setRightPanelVisible(false)}
              exportResult={exportResult}
              setExportResult={setExportResult}
              resultType={resultType}
              setResultType={setResultType}
            />
          </aside>
        )}

        <Button
          variant="outline"
          size="icon"
          onClick={() => setRightPanelVisible(!rightPanelVisible)}
          className={`hidden lg:flex fixed top-20 z-[70] h-8 w-5 shadow-lg transition-all rounded-l-full rounded-r-none border-r-0 ${
            rightPanelVisible ? 'right-[320px]' : 'right-0'
          }`}
          title={rightPanelVisible ? 'Close panel' : 'Open panel'}
        >
          {rightPanelVisible ? <ChevronRight className="h-3 w-3" /> : <ChevronLeft className="h-3 w-3" />}
        </Button>

        {!rightPanelVisible && (
          <FloatingActionButtons
            user={user}
            isLoggedIn={!!user}
            onOpenPanel={() => setRightPanelVisible(true)}
            onExport={handleExport}
            onQuiz={handleQuiz}
            onSummary={handleSummary}
          />
        )}
      </div>
    </div>
  );
}

export default App;
