import { useEffect, useRef, useState } from 'react'
import { Alert, Avatar, Button, Empty, Input, Message, Modal, Select, Spin, Tag, Typography } from '@arco-design/web-react'
import {
  IconApps, IconArrowLeft, IconArrowRight, IconCheckCircle, IconClockCircle,
  IconFile, IconFolder, IconPlus, IconRefresh, IconRobot, IconSearch, IconSettings,
} from '@arco-design/web-react/icon'
import {
  ApiError, checkServerConnection, createAISession, createCron, createProject, createTask, fetchAISessions, fetchExperts,
  fetchProjects, fetchWorkspace, login, updateTask, uploadSource,
  type AISession, type ApiSession, type Expert, type Project, type Workspace,
} from './api'

const { Text, Title } = Typography
type View = 'home' | 'tasks' | 'notes' | 'ai' | 'more'
type DockSide = 'left' | 'right'
type Action = 'project' | 'task' | 'cron' | null
type ConnectionStatus = 'checking' | 'online' | 'offline'

const navItems: Array<{ id: View; label: string; icon: React.ReactNode }> = [
  { id: 'home', label: '项目', icon: <IconApps /> },
  { id: 'tasks', label: '计划', icon: <IconCheckCircle /> },
  { id: 'notes', label: '资料', icon: <IconFile /> },
  { id: 'ai', label: 'AI', icon: <IconRobot /> },
  { id: 'more', label: '更多', icon: <IconSettings /> },
]

export function App() {
  const [session, setSession] = useState<ApiSession | null>(() => readStoredSession())
  const [projects, setProjects] = useState<Project[]>([])
  const [projectId, setProjectId] = useState('')
  const [workspace, setWorkspace] = useState<Workspace | null>(null)
  const [experts, setExperts] = useState<Expert[]>([])
  const [aiSessions, setAISessions] = useState<AISession[]>([])
  const [view, setView] = useState<View>('home')
  const [dockSide, setDockSide] = useState<DockSide>(() => {
    if ('__TAURI_INTERNALS__' in window) return 'right'
    return localStorage.getItem('senlin-mini-dock') === 'left' ? 'left' : 'right'
  })
  const [loading, setLoading] = useState(Boolean(session))
  const [error, setError] = useState('')
  const [action, setAction] = useState<Action>(null)
  const refreshGeneration = useRef(0)

  useEffect(() => {
    document.documentElement.dataset.dock = dockSide
    localStorage.setItem('senlin-mini-dock', dockSide)
    void moveDesktopWindow(dockSide)
  }, [dockSide])

  useEffect(() => {
    if (!session) return
    let cancelled = false
    setLoading(true)
    void fetchProjects(session)
      .then((items) => {
        if (cancelled) return
        setProjects(items)
        setProjectId((current) => items.some((item) => item.id === current) ? current : items[0]?.id ?? '')
      })
      .catch((requestError) => !cancelled && setError(errorMessage(requestError)))
      .finally(() => !cancelled && setLoading(false))
    return () => { cancelled = true }
  }, [session])

  useEffect(() => {
    if (!session || !projectId) return
    void refreshProject(session, projectId)
  }, [projectId, session])

  async function refreshProject(activeSession = session, activeProject = projectId) {
    if (!activeSession || !activeProject) return
    const generation = ++refreshGeneration.current
    setLoading(true)
    setError('')
    try {
      const [nextWorkspace, nextExperts, nextSessions] = await Promise.all([
        fetchWorkspace(activeSession, activeProject),
        experts.length ? Promise.resolve(experts) : fetchExperts(activeSession),
        fetchAISessions(activeSession, activeProject),
      ])
      if (generation !== refreshGeneration.current) return
      setWorkspace(nextWorkspace)
      setExperts(nextExperts)
      setAISessions(nextSessions)
    } catch (requestError) {
      if (generation === refreshGeneration.current) setError(errorMessage(requestError))
    } finally {
      if (generation === refreshGeneration.current) setLoading(false)
    }
  }

  async function dock(side: DockSide) {
    setDockSide(side)
  }

  if (!session) return <Login onLogin={(next) => { localStorage.setItem('senlin-mini-session', JSON.stringify(next)); setSession(next) }} />

  const activeProject = projects.find((project) => project.id === projectId) ?? projects[0]
  const content = !workspace || !activeProject
    ? <Empty description="还没有项目，点击右上角新建" />
    : renderView(view, {
        session, workspace, experts, aiSessions,
        refresh: () => refreshProject(),
        openAction: setAction,
      })

  return (
    <div className="mini-shell">
      <header className="mini-header" data-tauri-drag-region>
        <div className="mini-brand" data-tauri-drag-region>
          <img src="/senlinai-icon.svg" alt="" />
          <span>森林AI</span>
          <Tag size="small" color="arcoblue">Mini 1.0</Tag>
        </div>
        <div className="window-actions">
          <Button aria-label="停靠左侧" className={dockSide === 'left' ? 'active' : ''} type="text" size="mini" icon={<IconArrowLeft />} onClick={() => void dock('left')} />
          <Button aria-label="停靠右侧" className={dockSide === 'right' ? 'active' : ''} type="text" size="mini" icon={<IconArrowRight />} onClick={() => void dock('right')} />
        </div>
      </header>

      <div className="project-switcher">
        <Select
          value={projectId || undefined}
          placeholder="选择项目"
          onChange={setProjectId}
          triggerElement={() => (
            <button className="project-trigger">
              <Avatar size={26} style={{ background: activeProject?.background || '#165DFF' }}>{projectMark(activeProject)}</Avatar>
              <span>{activeProject?.name || '选择项目'}</span>
              <small>{activeProject?.identifier || ''}</small>
            </button>
          )}
        >
          {projects.map((project) => <Select.Option key={project.id} value={project.id}>{project.name}</Select.Option>)}
        </Select>
        <Button aria-label="刷新" type="text" shape="circle" icon={<IconRefresh />} loading={loading} onClick={() => void refreshProject()} />
        <Button aria-label="新建项目" type="text" shape="circle" icon={<IconPlus />} onClick={() => setAction('project')} />
      </div>

      <nav className="mini-nav" aria-label="主要导航">
        {navItems.map((item) => (
          <button className={view === item.id ? 'active' : ''} key={item.id} onClick={() => setView(item.id)}>
            {item.icon}<span>{item.label}</span>
          </button>
        ))}
      </nav>

      {error ? <Alert className="mini-alert" type="error" content={error} closable onClose={() => setError('')} /> : null}
      <main className="mini-content"><Spin loading={loading} block>{content}</Spin></main>

      <footer className="mini-footer">
        <span><i /> 服务已连接</span>
        <button onClick={() => { localStorage.removeItem('senlin-mini-session'); setSession(null); setWorkspace(null) }}>退出登录</button>
      </footer>

      <ActionModal
        action={action}
        workspace={workspace}
        onClose={() => setAction(null)}
        onProject={async (name) => {
          const project = await createProject(session, name)
          const next = await fetchProjects(session)
          setProjects(next)
          setProjectId(project.id)
        }}
        onTask={async (title, tag) => {
          if (!projectId) return
          await createTask(session, projectId, title, tag)
          await refreshProject()
        }}
        onCron={async (title, schedule) => {
          if (!projectId) return
          await createCron(session, projectId, title, schedule)
          await refreshProject()
        }}
      />
    </div>
  )
}

function renderView(view: View, props: ViewProps) {
  if (view === 'tasks') return <TasksView {...props} />
  if (view === 'notes') return <NotesView {...props} />
  if (view === 'ai') return <AIView {...props} />
  if (view === 'more') return <MoreView {...props} />
  return <HomeView {...props} />
}

type ViewProps = {
  session: ApiSession
  workspace: Workspace
  experts: Expert[]
  aiSessions: AISession[]
  refresh: () => void | Promise<void>
  openAction: (action: Action) => void
}

function HomeView({ workspace, openAction }: ViewProps) {
  const pending = workspace.tasks.filter((task) => !task.completed)
  return (
    <section className="mini-page home-view">
      <div className="page-intro">
        <Text type="secondary">当前项目</Text>
        <Title heading={4}>{workspace.project.name}</Title>
        <p>{workspace.project.description || '把计划、资料与 AI 会话放进同一个项目上下文。'}</p>
      </div>
      <div className="metric-grid">
        <Metric value={pending.length} label="待办计划" color="blue" />
        <Metric value={workspace.notesSources.length} label="笔记资料" color="green" />
        <Metric value={workspace.aiSessions.length} label="AI 会话" color="purple" />
        <Metric value={workspace.cronPlans.length} label="计划任务" color="orange" />
      </div>
      <div className="section-title"><strong>快速操作</strong></div>
      <div className="quick-actions">
        <button onClick={() => openAction('task')}><IconPlus /><span><b>新建计划</b><small>快速记录下一步</small></span></button>
        <button onClick={() => openAction('cron')}><IconClockCircle /><span><b>计划任务</b><small>添加周期安排</small></span></button>
      </div>
      <div className="section-title"><strong>接下来</strong><Tag color="arcoblue">{pending.length}</Tag></div>
      <div className="compact-list">
        {pending.slice(0, 4).map((task) => <div key={task.id}><IconCheckCircle /><span><b>{task.title}</b><small>{task.tag || '未分类'}</small></span></div>)}
        {!pending.length && <Empty description="当前没有未完成计划" />}
      </div>
    </section>
  )
}

function Metric({ value, label, color }: { value: number; label: string; color: string }) {
  return <div className={`metric ${color}`}><strong>{value}</strong><span>{label}</span></div>
}

function TasksView({ session, workspace, refresh, openAction }: ViewProps) {
  const [tag, setTag] = useState('全部')
  const tags = workspace.tags.filter((item) => item.name !== '全部' && item.name !== 'all')
  const tasks = tag === '全部' ? workspace.tasks : workspace.tasks.filter((task) => task.tag === tag)
  return (
    <section className="mini-page">
      <div className="page-title"><div><Title heading={5}>工作计划</Title><Text type="secondary">轻点圆圈即可更新状态</Text></div><Button type="primary" size="small" icon={<IconPlus />} onClick={() => openAction('task')}>新建</Button></div>
      <div className="filter-strip">
        {['全部', ...tags.map((item) => item.name)].map((item) => <button className={tag === item ? 'active' : ''} key={item} onClick={() => setTag(item)}>{item}</button>)}
      </div>
      <div className="sticky-list">
        {tasks.map((task) => (
          <article className={task.completed ? 'task-note completed' : 'task-note'} key={task.id}>
            <button className="task-check" aria-label={task.completed ? '恢复计划' : '完成计划'} onClick={async () => { await updateTask(session, workspace.project.id, task); await refresh() }}><IconCheckCircle /></button>
            <div><strong>{task.title}</strong><p>{task.summary || '暂无说明'}</p><span>{task.tag || '未分类'} · {task.createdAt}</span></div>
          </article>
        ))}
        {!tasks.length && <Empty description="当前筛选下没有计划" />}
      </div>
    </section>
  )
}

function NotesView({ session, workspace, refresh }: ViewProps) {
  const fileInput = useRef<HTMLInputElement>(null)
  return (
    <section className="mini-page">
      <div className="page-title"><div><Title heading={5}>笔记资料</Title><Text type="secondary">项目资料随手可取</Text></div><Button type="primary" size="small" icon={<IconPlus />} onClick={() => fileInput.current?.click()}>上传</Button></div>
      <input className="hidden-file" ref={fileInput} type="file" onChange={async (event) => { const file = event.target.files?.[0]; if (!file) return; await uploadSource(session, workspace.project.id, file); await refresh(); event.target.value = '' }} />
      <div className="note-grid">
        {workspace.notesSources.map((note, index) => <article className={`source-note tone-${index % 4}`} key={note.id}><IconFile /><strong>{note.title}</strong><p>{note.source || note.kind}</p><span>{note.tag || '资料'} · {note.updatedAt}</span></article>)}
        {!workspace.notesSources.length && <Empty description="还没有笔记或资料" />}
      </div>
    </section>
  )
}

function AIView({ session, workspace, experts, aiSessions, refresh }: ViewProps) {
  const [query, setQuery] = useState('')
  const [category, setCategory] = useState('全部')
  const [expertId, setExpertId] = useState('')
  const [prompt, setPrompt] = useState('')
  const [sending, setSending] = useState(false)
  const categories = [...new Set(experts.map((expert) => expert.categoryName))]
  const visible = experts.filter((expert) => (category === '全部' || expert.categoryName === category) && `${expert.name}${expert.description}`.toLowerCase().includes(query.toLowerCase()))
  const selected = experts.find((expert) => expert.id === expertId)
  return (
    <section className="mini-page ai-view">
      <div className="page-title"><div><Title heading={5}>AI 会话</Title><Text type="secondary">先选择专家，再开始会话</Text></div><Tag color="purple">{experts.length} 位</Tag></div>
      <Input prefix={<IconSearch />} value={query} onChange={setQuery} allowClear placeholder="搜索专家" />
      <div className="filter-strip">
        {['全部', ...categories].map((item) => <button className={category === item ? 'active' : ''} key={item} onClick={() => setCategory(item)}>{item}</button>)}
      </div>
      <div className="expert-strip">
        {visible.slice(0, 30).map((expert) => <button className={expertId === expert.id ? 'active' : ''} key={expert.id} onClick={() => setExpertId(expert.id)}><i style={{ background: expert.color }}>{expert.emoji}</i><span><b>{expert.name}</b><small>{expert.categoryName}</small></span></button>)}
      </div>
      <div className="mini-composer">
        <div className="selected-expert">{selected ? <><i style={{ background: selected.color }}>{selected.emoji}</i><span><b>{selected.name}</b><small>{selected.description}</small></span></> : <Text type="secondary">选择一位专家进行会话</Text>}</div>
        <Input.TextArea value={prompt} onChange={setPrompt} autoSize={{ minRows: 3, maxRows: 6 }} placeholder={selected ? `向${selected.name}发送消息` : '请先选择专家'} />
        <Button type="primary" long loading={sending} disabled={!selected || !prompt.trim()} onClick={async () => { if (!selected) return; setSending(true); try { await createAISession(session, workspace.project.id, selected.id, prompt.trim()); setPrompt(''); await refresh() } finally { setSending(false) } }}>开始会话</Button>
      </div>
      <div className="section-title"><strong>最近会话</strong></div>
      <div className="session-list">{aiSessions.slice(0, 5).map((item) => <div key={item.id}><i style={{ background: item.expert?.color }}>{item.expert?.emoji || '🤖'}</i><span><b>{item.title}</b><small>{item.expert?.name || '森林AI'}</small></span></div>)}</div>
    </section>
  )
}

function MoreView({ workspace, openAction }: ViewProps) {
  return (
    <section className="mini-page">
      <div className="page-title"><div><Title heading={5}>更多</Title><Text type="secondary">项目周期安排与客户端信息</Text></div><Button size="small" icon={<IconPlus />} onClick={() => openAction('cron')}>计划任务</Button></div>
      <div className="settings-card"><strong>计划任务</strong>{workspace.cronPlans.map((plan) => <div key={plan.id}><IconClockCircle /><span><b>{plan.title}</b><small>{plan.schedule} · {plan.enabled ? '已启用' : '已停用'}</small></span></div>)}{!workspace.cronPlans.length && <Text type="secondary">暂无周期计划</Text>}</div>
      <div className="settings-card"><strong>停靠说明</strong><p>顶部箭头可将桌面窗口停靠至当前屏幕左侧或右侧。Web 模式会记住布局偏好，桌面模式会同时移动实际窗口。</p></div>
      <div className="settings-card version-card"><img src="/senlinai-icon.svg" alt="" /><span><b>森林AI Mini</b><small>v1.0 完整版 · 窄屏停靠客户端</small></span></div>
    </section>
  )
}

function Login({ onLogin }: { onLogin: (session: ApiSession) => void }) {
  const [server, setServer] = useState('http://localhost:9150')
  const [email, setEmail] = useState('demo@senlin.ai')
  const [password, setPassword] = useState('password123')
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')
  const [connection, setConnection] = useState<ConnectionStatus>('checking')

  useEffect(() => {
    const controller = new AbortController()
    const timer = window.setTimeout(() => void checkConnection(controller.signal), 300)
    return () => {
      controller.abort()
      window.clearTimeout(timer)
    }
  }, [server])

  async function checkConnection(signal?: AbortSignal) {
    setConnection('checking')
    try {
      const online = await checkServerConnection(server, signal)
      if (!signal?.aborted) setConnection(online ? 'online' : 'offline')
    } catch (requestError) {
      if (!(requestError instanceof DOMException && requestError.name === 'AbortError')) setConnection('offline')
    }
  }

  async function submitLogin() {
    if (loading) return
    setLoading(true)
    setError('')
    try {
      onLogin(await login(server, email.trim(), password))
    } catch (requestError) {
      setError(errorMessage(requestError))
    } finally {
      setLoading(false)
    }
  }

  return (
    <div className="mini-login">
      <form className="login-note" onSubmit={(event) => { event.preventDefault(); void submitLogin() }}>
        <img src="/senlinai-icon.svg" alt="" />
        <Title heading={3}>森林AI Mini</Title>
        <Text type="secondary">停靠在屏幕一侧，随时记录与推进项目</Text>
        <label>服务器地址<Input value={server} onChange={setServer} /></label>
        <div className={`mini-connection ${connection}`} role="status">
          <i />
          <strong>{connection === 'checking' ? '正在检查' : connection === 'online' ? '连接正常' : '连接异常'}</strong>
          <button type="button" onClick={() => void checkConnection()}>{connection === 'checking' ? '检查中' : '重新检查'}</button>
        </div>
        <label>邮箱<Input value={email} onChange={setEmail} /></label>
        <label>密码<Input.Password value={password} onChange={setPassword} /></label>
        {error ? <Alert type="error" content={error} /> : null}
        <Button type="primary" htmlType="submit" long loading={loading}>连接工作台</Button>
        <small>v1.0 完整版</small>
      </form>
    </div>
  )
}

function ActionModal({ action, workspace, onClose, onProject, onTask, onCron }: {
  action: Action
  workspace: Workspace | null
  onClose: () => void
  onProject: (name: string) => Promise<void>
  onTask: (title: string, tag: string) => Promise<void>
  onCron: (title: string, schedule: string) => Promise<void>
}) {
  const [title, setTitle] = useState('')
  const [tag, setTag] = useState('')
  const [schedule, setSchedule] = useState('0 9 * * 1-5')
  const [loading, setLoading] = useState(false)
  useEffect(() => { if (action) { setTitle(''); setTag(''); setSchedule('0 9 * * 1-5') } }, [action])
  const labels = action === 'project' ? ['新建项目', '项目名称'] : action === 'task' ? ['新建计划', '计划标题'] : ['新建计划任务', '任务名称']
  return (
    <Modal className="mini-modal" visible={Boolean(action)} title={labels[0]} onCancel={onClose} footer={null} unmountOnExit>
      <div className="mini-form">
        <label>{labels[1]}<Input autoFocus value={title} onChange={setTitle} /></label>
        {action === 'task' ? <label>标签<Select value={tag || undefined} placeholder="可选" onChange={setTag}>{workspace?.tags.filter((item) => item.name !== 'all' && item.name !== '全部').map((item) => <Select.Option key={item.id} value={item.name}>{item.name}</Select.Option>)}</Select></label> : null}
        {action === 'cron' ? <label>Cron 表达式<Input value={schedule} onChange={setSchedule} /></label> : null}
        <Button type="primary" long loading={loading} disabled={!title.trim()} onClick={async () => { setLoading(true); try { if (action === 'project') await onProject(title.trim()); if (action === 'task') await onTask(title.trim(), tag); if (action === 'cron') await onCron(title.trim(), schedule.trim()); onClose() } catch (requestError) { Message.error(errorMessage(requestError)) } finally { setLoading(false) } }}>保存</Button>
      </div>
    </Modal>
  )
}

function readStoredSession(): ApiSession | null {
  try {
    const value = JSON.parse(localStorage.getItem('senlin-mini-session') || 'null') as ApiSession | null
    return value?.baseUrl && value?.token ? value : null
  } catch {
    return null
  }
}

function projectMark(project?: Project) {
  if (!project) return <IconFolder />
  if (project.icon && !['folder', 'project'].includes(project.icon)) return project.icon
  const chars = Array.from(project.name.trim())
  const chinese = chars.some((char) => /[\u3400-\u9fff]/.test(char))
  return chars.slice(0, chinese ? 2 : 4).join('').toUpperCase()
}

function errorMessage(error: unknown) {
  if (error instanceof ApiError || error instanceof Error) return error.message
  return '操作失败，请稍后重试'
}

async function moveDesktopWindow(side: DockSide) {
  if (!('__TAURI_INTERNALS__' in window)) return
  try {
    const { invoke } = await import('@tauri-apps/api/core')
    await invoke('dock_window', { side })
  } catch (requestError) {
    Message.warning(errorMessage(requestError))
  }
}
