import { useEffect, useMemo, useState } from 'react'
import { api, type Agent, type EnvVar, type Task } from '@/api'
import { PATHS, TRIGGER_TYPE } from '@/constants'
import { TagInput } from '@/components/business/TagInput'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import { Field } from '@/components/ui/field'
import { Input } from '@/components/ui/input'
import { Modal } from '@/components/ui/modal'
import { Select } from '@/components/ui/select'
import { Switch } from '@/components/ui/switch'
import { Textarea } from '@/components/ui/textarea'

type LangItem = { name: string; version: string }

const emptyForm = (): Partial<Task> => ({
  name: '',
  remark: '',
  command: '',
  pre_command: '',
  post_command: '',
  schedule: '0 * * * * *',
  timeout: 30,
  work_dir: '',
  tags: '',
  type: 'task',
  trigger_type: TRIGGER_TYPE.CRON,
  enabled: true,
  clean_config: '',
  envs: '',
  retry_count: 0,
  retry_interval: 0,
  random_range: 0,
  pin_type: 'none',
  languages: [],
  agent_id: null,
  config: '{}',
})

export function TaskDialog({
  open,
  task,
  isEdit,
  onClose,
  onSaved,
}: {
  open: boolean
  task?: Partial<Task>
  isEdit: boolean
  onClose: () => void
  onSaved: () => void
}) {
  const [form, setForm] = useState<Partial<Task>>(emptyForm())
  const [agents, setAgents] = useState<Agent[]>([])
  const [envs, setEnvs] = useState<EnvVar[]>([])
  const [selectedEnvIds, setSelectedEnvIds] = useState<string[]>([])
  const [agentId, setAgentId] = useState('local')
  const [triggerType, setTriggerType] = useState<string>(TRIGGER_TYPE.CRON)
  const [langs, setLangs] = useState<LangItem[]>([])
  const [langName, setLangName] = useState('python')
  const [langVersion, setLangVersion] = useState('')
  const [allEnvs, setAllEnvs] = useState(false)
  const [commentToTask, setCommentToTask] = useState(false)
  const [scriptsDir, setScriptsDir] = useState(PATHS.SCRIPTS_DIR)
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState('')
  const [notifyChannels, setNotifyChannels] = useState<{ id: string; name: string }[]>([])
  const [notifyChannelId, setNotifyChannelId] = useState('')
  const [notifyEvents, setNotifyEvents] = useState('success,failed')

  const onlineAgents = useMemo(() => agents.filter((a) => a.enabled !== false), [agents])

  useEffect(() => {
    if (!open) return
    setError('')
    const base = { ...emptyForm(), ...task }
    setForm(base)
    setAgentId(task?.agent_id ? String(task.agent_id) : 'local')
    setTriggerType(task?.trigger_type || TRIGGER_TYPE.CRON)
    setSelectedEnvIds(
      task?.envs
        ? task.envs
            .split(',')
            .map((s) => s.trim())
            .filter(Boolean)
        : [],
    )
    setLangs(Array.isArray(task?.languages) ? task!.languages!.map((l) => ({ name: l.name, version: l.version })) : [])
    try {
      const cfg = JSON.parse(task?.config || '{}')
      setAllEnvs(!!cfg['$task_all_envs'])
      setCommentToTask(!!cfg['$task_comment_to_task'])
    } catch {
      setAllEnvs(false)
      setCommentToTask(false)
    }

    ;(async () => {
      try {
        const [envList, agentList, paths, channels, bindings] = await Promise.all([
          api.env.all().catch(() => []),
          api.agents.list().catch(() => []),
          api.settings.getPaths().catch(() => ({ scripts_dir: PATHS.SCRIPTS_DIR })),
          api.notify.getChannels().catch(() => []),
          isEdit && task?.id ? api.notify.getBindings().catch(() => []) : Promise.resolve([]),
        ])
        setEnvs(Array.isArray(envList) ? envList : [])
        setAgents(Array.isArray(agentList) ? agentList : [])
        setScriptsDir(paths?.scripts_dir || PATHS.SCRIPTS_DIR)
        setNotifyChannels(
          (Array.isArray(channels) ? channels : []).map((c: any) => ({ id: c.id, name: c.name || c.id })),
        )
        if (isEdit && task?.id && Array.isArray(bindings)) {
          const mine = bindings.filter((b: any) => b.data_id === task.id && (b.type === 'task' || !b.type))
          if (mine[0]) {
            const b = mine[0] as any
            setNotifyChannelId(b.way_id || b.channel_id || '')
            setNotifyEvents(b.event || b.events || 'success,failed')
          }
        }
      } catch {
        // ignore
      }
    })()
  }, [open, task, isEdit])

  function patch<K extends keyof Task>(key: K, value: Task[K]) {
    setForm((f) => ({ ...f, [key]: value }))
  }

  function encodeLocalWorkDir(workDir?: string | null) {
    const value = workDir?.trim() || ''
    if (!value) return PATHS.SCRIPTS_DIR_PLACEHOLDER
    if (value === PATHS.SCRIPTS_DIR_PLACEHOLDER || value.startsWith(`${PATHS.SCRIPTS_DIR_PLACEHOLDER}/`)) return value
    const base = scriptsDir || PATHS.SCRIPTS_DIR
    if (value === base) return PATHS.SCRIPTS_DIR_PLACEHOLDER
    if (value.startsWith(`${base}/`)) return `${PATHS.SCRIPTS_DIR_PLACEHOLDER}/${value.slice(base.length + 1)}`
    return `${PATHS.SCRIPTS_DIR_PLACEHOLDER}/${value.replace(/^\/+/, '')}`
  }

  async function save() {
    if (!form.name?.trim()) {
      setError('请填写任务名称')
      return
    }
    if (!form.command?.trim() && form.type !== 'repo') {
      setError('请填写执行命令')
      return
    }
    setSaving(true)
    setError('')
    try {
      let config: Record<string, any> = {}
      try {
        config = form.config ? JSON.parse(form.config) : {}
      } catch {
        config = {}
      }
      config['$task_all_envs'] = allEnvs
      config['$task_comment_to_task'] = commentToTask

      const payload: Partial<Task> = {
        ...form,
        name: form.name!.trim(),
        type: form.type || 'task',
        trigger_type: triggerType,
        agent_id: agentId === 'local' ? null : agentId,
        envs: selectedEnvIds.join(','),
        languages: langs,
        config: JSON.stringify(config),
        work_dir: agentId === 'local' ? encodeLocalWorkDir(form.work_dir) : form.work_dir || '',
      }

      let saved: Task
      if (isEdit && form.id) {
        saved = await api.tasks.update(form.id, payload)
      } else {
        saved = await api.tasks.create(payload)
      }

      if (notifyChannelId && saved?.id) {
        try {
          const events = notifyEvents
            .split(',')
            .map((s) => s.trim())
            .filter(Boolean)
          await api.notify.saveBindingsBatch({
            type: 'task',
            data_id: saved.id,
            bindings: events.map((event) => ({
              type: 'task',
              event,
              way_id: notifyChannelId,
              data_id: saved.id,
            })),
          })
        } catch {
          // 通知绑定失败不阻断任务保存
        }
      }

      onSaved()
      onClose()
    } catch (e: any) {
      setError(e?.message || '保存失败')
    } finally {
      setSaving(false)
    }
  }

  return (
    <Modal
      open={open}
      title={isEdit ? '编辑任务' : '新建任务'}
      onClose={onClose}
      size="xl"
      footer={
        <>
          <Button variant="secondary" onClick={onClose}>
            取消
          </Button>
          <Button onClick={save} disabled={saving}>
            {saving ? '保存中...' : '保存'}
          </Button>
        </>
      }
    >
      {error ? <div className="rounded-md bg-[color-mix(in_srgb,var(--danger)_14%,transparent)] px-3 py-2 text-sm text-[var(--danger)]">{error}</div> : null}

      <Section title="基本信息">
        <Field label="任务名称">
          <Input value={form.name || ''} onChange={(e) => patch('name', e.target.value)} placeholder="输入任务名称" />
        </Field>
        <Field label="备注">
          <Input value={form.remark || ''} onChange={(e) => patch('remark', e.target.value)} placeholder="可选" />
        </Field>
        <Field label="标签">
          <TagInput value={form.tags || ''} onChange={(v) => patch('tags', v)} />
        </Field>
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="执行位置">
            <Select value={agentId} onChange={(e) => setAgentId(e.target.value)}>
              <option value="local">本地执行</option>
              {onlineAgents.map((a) => (
                <option key={a.id} value={String(a.id)}>
                  {a.name || a.id} {a.status === 'online' ? '(在线)' : ''}
                </option>
              ))}
            </Select>
          </Field>
          <Field label="触发方式">
            <Select value={triggerType} onChange={(e) => setTriggerType(e.target.value)}>
              <option value={TRIGGER_TYPE.CRON}>定时周期</option>
              <option value={TRIGGER_TYPE.TASKPOOL_STARTUP}>系统启动</option>
            </Select>
          </Field>
        </div>
      </Section>

      <Section title="执行配置">
        {agentId === 'local' ? (
          <div className="space-y-2">
            <div className="rounded-md border border-amber-500/20 bg-amber-500/5 p-3 text-xs text-amber-600 dark:text-amber-400">
              请先在「语言依赖」中安装运行时。脚本执行将自动注入对应环境。
            </div>
            <Field label="语言环境">
              <div className="flex flex-wrap gap-2">
                <Select value={langName} onChange={(e) => setLangName(e.target.value)} className="max-w-[140px]">
                  {['python', 'node', 'go', 'php', 'ruby', 'java', 'bun', 'deno'].map((n) => (
                    <option key={n} value={n}>
                      {n}
                    </option>
                  ))}
                </Select>
                <Input className="max-w-[140px]" placeholder="版本，可空" value={langVersion} onChange={(e) => setLangVersion(e.target.value)} />
                <Button
                  type="button"
                  variant="secondary"
                  onClick={() => {
                    if (!langName) return
                    setLangs((prev) => [...prev, { name: langName, version: langVersion }])
                    setLangVersion('')
                  }}
                >
                  添加
                </Button>
              </div>
              <div className="mt-2 flex flex-wrap gap-1.5">
                {langs.map((l, i) => (
                  <button
                    key={`${l.name}-${l.version}-${i}`}
                    type="button"
                    className="rounded bg-[var(--bg-selected)] px-2 py-0.5 text-xs"
                    onClick={() => setLangs((prev) => prev.filter((_, idx) => idx !== i))}
                    title="点击移除"
                  >
                    {l.name}
                    {l.version ? `@${l.version}` : ''} ×
                  </button>
                ))}
              </div>
            </Field>
          </div>
        ) : null}

        {triggerType === TRIGGER_TYPE.CRON ? (
          <Field label="Cron 表达式">
            <Input
              value={form.schedule || ''}
              onChange={(e) => patch('schedule', e.target.value)}
              placeholder="秒 分 时 日 月 周，如 0 */5 * * * *"
            />
            <div className="mt-1 flex flex-wrap gap-1">
              {[
                ['每分钟', '0 * * * * *'],
                ['每小时', '0 0 * * * *'],
                ['每天0点', '0 0 0 * * *'],
                ['每5分钟', '0 */5 * * * *'],
              ].map(([label, expr]) => (
                <Button key={expr} type="button" size="sm" variant="ghost" onClick={() => patch('schedule', expr)}>
                  {label}
                </Button>
              ))}
            </div>
          </Field>
        ) : null}

        <Field label="执行命令">
          <Textarea
            className="min-h-28 font-mono text-xs"
            value={form.command || ''}
            onChange={(e) => patch('command', e.target.value)}
            placeholder="例如: python main.py"
          />
        </Field>
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="前置命令">
            <Textarea value={form.pre_command || ''} onChange={(e) => patch('pre_command', e.target.value)} placeholder="可选" />
          </Field>
          <Field label="后置命令">
            <Textarea value={form.post_command || ''} onChange={(e) => patch('post_command', e.target.value)} placeholder="可选" />
          </Field>
        </div>
        <Field label="工作目录">
          <Input value={form.work_dir || ''} onChange={(e) => patch('work_dir', e.target.value)} placeholder={agentId === 'local' ? '相对 scripts 目录，可空' : '远程工作目录'} />
        </Field>
      </Section>

      <Section title="环境变量">
        <div className="mb-2 flex items-center gap-2 text-sm">
          <Checkbox checked={allEnvs} onCheckedChange={setAllEnvs} />
          <span>注入全部环境变量</span>
        </div>
        {!allEnvs ? (
          <>
            <Select
              value=""
              onChange={(e) => {
                const id = e.target.value
                if (id && !selectedEnvIds.includes(id)) setSelectedEnvIds((ids) => [...ids, id])
              }}
            >
              <option value="">添加变量...</option>
              {envs
                .filter((e) => !selectedEnvIds.includes(e.id))
                .map((e) => (
                  <option key={e.id} value={e.id}>
                    {e.name}
                    {e.remark ? ` · ${e.remark}` : ''}
                  </option>
                ))}
            </Select>
            <div className="mt-2 flex flex-wrap gap-1.5">
              {selectedEnvIds.map((id) => {
                const env = envs.find((e) => e.id === id)
                return (
                  <button
                    key={id}
                    type="button"
                    className="rounded bg-[var(--bg-selected)] px-2 py-0.5 text-xs"
                    onClick={() => setSelectedEnvIds((ids) => ids.filter((x) => x !== id))}
                  >
                    {env?.name || id} ×
                  </button>
                )
              })}
            </div>
          </>
        ) : null}
      </Section>

      <Section title="高级配置">
        <div className="grid gap-3 sm:grid-cols-3">
          <Field label="超时(秒)">
            <Input type="number" value={form.timeout ?? 30} onChange={(e) => patch('timeout', Number(e.target.value) || 0)} />
          </Field>
          <Field label="重试次数">
            <Input type="number" value={form.retry_count ?? 0} onChange={(e) => patch('retry_count', Number(e.target.value) || 0)} />
          </Field>
          <Field label="重试间隔(秒)">
            <Input type="number" value={form.retry_interval ?? 0} onChange={(e) => patch('retry_interval', Number(e.target.value) || 0)} />
          </Field>
        </div>
        <Field label="随机延迟(秒)">
          <Input type="number" value={form.random_range ?? 0} onChange={(e) => patch('random_range', Number(e.target.value) || 0)} />
        </Field>
        <div className="flex items-center justify-between rounded-md border border-[var(--border)] px-3 py-2">
          <span className="text-sm">注释解析为任务参数</span>
          <Switch checked={commentToTask} onCheckedChange={setCommentToTask} />
        </div>
        <div className="flex items-center justify-between rounded-md border border-[var(--border)] px-3 py-2">
          <span className="text-sm">启用任务</span>
          <Switch checked={!!form.enabled} onCheckedChange={(v) => patch('enabled', v)} />
        </div>
      </Section>

      <Section title="消息通知">
        <Field label="推送渠道">
          <Select value={notifyChannelId} onChange={(e) => setNotifyChannelId(e.target.value)}>
            <option value="">不绑定</option>
            {notifyChannels.map((c) => (
              <option key={c.id} value={c.id}>
                {c.name}
              </option>
            ))}
          </Select>
        </Field>
        {notifyChannelId ? (
          <Field label="事件(逗号分隔)">
            <Input value={notifyEvents} onChange={(e) => setNotifyEvents(e.target.value)} placeholder="success,failed,timeout" />
          </Field>
        ) : null}
      </Section>
    </Modal>
  )
}

function Section({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <section className="space-y-3 border-b border-[var(--border)] pb-4 last:border-0">
      <div className="flex items-center gap-2">
        <div className="h-3.5 w-1 rounded-full bg-[var(--bg-accent)]" />
        <h4 className="text-sm font-semibold">{title}</h4>
      </div>
      <div className="space-y-3 pl-3">{children}</div>
    </section>
  )
}
