/**
 * 任务管理页面。
 *
 * 三个 Tab：队列、调度、历史
 * 队列 Tab：running 状态的任务可点击查看实时 WebSocket 日志流
 * 历史 Tab：点击记录可查看执行详情和历史日志
 */

import React, { useEffect, useState, useCallback, useRef } from 'react';
import { useSearchParams } from 'react-router-dom';
import {
  Tabs, Table, Tag, Button, Popconfirm, Space, message, Drawer,
  Typography, Descriptions, Empty, Spin,
} from 'antd';
import {
  ReloadOutlined, DeleteOutlined, StopOutlined,
  UnorderedListOutlined, ClockCircleOutlined, HistoryOutlined,
  FileTextOutlined, PlayCircleOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import type { QueuedTask, ExecutionLog } from '../types';
import {
  fetchQueue, fetchHistory, deleteFromQueue, cancelExecution, rerunExecution,
} from '../api/execution';
import { apiClient } from '../api/client';
import LogStream from '../components/LogStream';
import ScheduleTab from '../components/ScheduleTab';

const { Title, Text } = Typography;

/* ------------------------------------------------------------------ */
/*  状态颜色映射                                                       */
/* ------------------------------------------------------------------ */

const STATUS_COLOR: Record<string, string> = {
  pending: 'default',
  running: 'processing',
  success: 'success',
  failed: 'error',
  cancelled: 'warning',
  interrupted: 'volcano',
};

/* ------------------------------------------------------------------ */
/*  工具函数                                                           */
/* ------------------------------------------------------------------ */

function fmtTime(iso: string | null | undefined): string {
  if (!iso) return '—';
  return new Date(iso).toLocaleString('zh-CN');
}

function fmtDuration(ms: number | null | undefined): string {
  if (ms == null) return '—';
  if (ms < 1000) return `${ms}ms`;
  const sec = ms / 1000;
  if (sec < 60) return `${sec.toFixed(1)}s`;
  const min = Math.floor(sec / 60);
  const remainSec = Math.round(sec % 60);
  return `${min}m${remainSec}s`;
}

/* ------------------------------------------------------------------ */
/*  队列 Tab                                                           */
/* ------------------------------------------------------------------ */

export const QueueTab: React.FC = () => {
  const [data, setData] = useState<QueuedTask[]>([]);
  const [loading, setLoading] = useState(false);

  /* WebSocket 日志流状态 */
  const [logDrawerOpen, setLogDrawerOpen] = useState(false);
  const [logLines, setLogLines] = useState<string[]>([]);
  const [logTaskId, setLogTaskId] = useState<string | null>(null);
  const [wsConnected, setWsConnected] = useState(false);
  const wsRef = useRef<WebSocket | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    try { setData(await fetchQueue()); }
    catch { message.error('加载队列失败'); }
    finally { setLoading(false); }
  }, []);

  useEffect(() => { load(); }, [load]);

  /* 自动轮询队列状态（5 秒间隔），保持状态实时 */
  useEffect(() => {
    const timer = setInterval(load, 5_000);
    return () => clearInterval(timer);
  }, [load]);

  /* 组件卸载时关闭 WebSocket */
  useEffect(() => {
    return () => { wsRef.current?.close(); };
  }, []);

  /** 打开日志抽屉并建立 WebSocket 连接 */
  const handleViewLogs = useCallback((taskId: string) => {
    setLogTaskId(taskId);
    setLogLines([]);
    setLogDrawerOpen(true);

    // 关闭旧连接
    wsRef.current?.close();

    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const host = window.location.host;
    const ws = new WebSocket(`${protocol}//${host}/ws/logs/${taskId}`);
    wsRef.current = ws;

    ws.onopen = () => { setWsConnected(true); };
    ws.onmessage = (event) => {
      setLogLines((prev) => [...prev, event.data]);
    };
    ws.onclose = () => { setWsConnected(false); };
    ws.onerror = () => {
      message.error('WebSocket 连接失败');
      setWsConnected(false);
    };
  }, []);

  /** 关闭日志抽屉 */
  const handleCloseLogDrawer = useCallback(() => {
    setLogDrawerOpen(false);
    wsRef.current?.close();
    wsRef.current = null;
    setWsConnected(false);
    setLogTaskId(null);
  }, []);

  const handleDelete = async (id: string) => {
    try { await deleteFromQueue(id); message.success('已删除'); load(); }
    catch { message.error('删除失败'); }
  };

  const handleCancel = async (id: string) => {
    try { await cancelExecution(id); message.success('已取消'); load(); }
    catch { message.error('取消失败'); }
  };

  const columns: ColumnsType<QueuedTask> = [
    {
      title: '任务 ID', dataIndex: 'id', key: 'id', width: 120,
      render: (id: string) => (
        <Text copyable={{ text: id }} style={{ fontSize: 11 }}>
          {id.slice(0, 8)}…
        </Text>
      ),
    },
    {
      title: '任务', dataIndex: ['config', 'tasks'], key: 'tasks',
      render: (tasks: string[]) => (
        <Text style={{ maxWidth: 300 }} ellipsis={{ tooltip: tasks?.join(', ') }}>
          {tasks?.join(', ') ?? '—'}
        </Text>
      ),
    },
    {
      title: 'Flow', dataIndex: ['config', 'flow'], key: 'flow', width: 120,
      render: (v: string) => <Tag>{v}</Tag>,
    },
    {
      title: '状态', dataIndex: 'status', key: 'status', width: 90,
      render: (s: string) => <Tag color={STATUS_COLOR[s] ?? 'default'}>{s}</Tag>,
    },
    { title: '位置', dataIndex: 'position', key: 'position', width: 60, align: 'center' },
    { title: '创建时间', dataIndex: 'created_at', key: 'created_at', width: 170, render: fmtTime },
    {
      title: '操作', key: 'action', width: 160, align: 'center',
      render: (_: unknown, record: QueuedTask) => {
        if (record.status === 'pending') {
          return (
            <Popconfirm title="确认删除？" onConfirm={() => handleDelete(record.id)}>
              <Button type="link" danger icon={<DeleteOutlined />} size="small">删除</Button>
            </Popconfirm>
          );
        }
        if (record.status === 'running') {
          return (
            <Space size={4}>
              <Button
                type="link" icon={<FileTextOutlined />} size="small"
                onClick={() => handleViewLogs(record.id)}
              >
                日志
              </Button>
              <Popconfirm title="确认取消执行？" onConfirm={() => handleCancel(record.id)}>
                <Button type="link" danger icon={<StopOutlined />} size="small">取消</Button>
              </Popconfirm>
            </Space>
          );
        }
        return null;
      },
    },
  ];

  return (
    <>
      <div style={{ marginBottom: 12, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <Text type="secondary">共 {data.length} 个任务</Text>
        <Button icon={<ReloadOutlined />} onClick={load} loading={loading}>刷新</Button>
      </div>
      <Table<QueuedTask>
        rowKey="id" columns={columns} dataSource={data}
        loading={loading} pagination={false} size="small"
        locale={{ emptyText: <Empty description="队列为空" /> }}
      />

      {/* 实时日志抽屉 */}
      <Drawer
        title={
          <Space>
            <FileTextOutlined />
            <span>执行日志</span>
            {wsConnected
              ? <Tag color="processing">实时连接中</Tag>
              : <Tag>未连接</Tag>}
          </Space>
        }
        open={logDrawerOpen}
        onClose={handleCloseLogDrawer}
        width={720}
        styles={{ body: { padding: 12, display: 'flex', flexDirection: 'column', height: '100%' } }}
      >
        {logTaskId && (
          <div style={{ flex: 1, minHeight: 0 }}>
            <LogStream executionId={logTaskId} lines={logLines} />
          </div>
        )}
      </Drawer>
    </>
  );
};

/* ------------------------------------------------------------------ */
/*  历史 Tab                                                           */
/* ------------------------------------------------------------------ */

export const HistoryTab: React.FC = () => {
  const [data, setData] = useState<ExecutionLog[]>([]);
  const [loading, setLoading] = useState(false);
  const [detail, setDetail] = useState<ExecutionLog | null>(null);
  const [historyLogLines, setHistoryLogLines] = useState<string[]>([]);
  const [logLoading, setLogLoading] = useState(false);
  const [wsConnected, setWsConnected] = useState(false);
  const historyWsRef = useRef<WebSocket | null>(null);

  /** 关闭 WebSocket 连接并重置状态 */
  const closeHistoryWs = useCallback(() => {
    historyWsRef.current?.close();
    historyWsRef.current = null;
    setWsConnected(false);
  }, []);

  /* 组件卸载时清理 WebSocket */
  useEffect(() => {
    return () => { historyWsRef.current?.close(); };
  }, []);

  const handleCancelHistory = useCallback(async (id: string) => {
    try { await cancelExecution(id); message.success('已发送终止信号'); load(); }
    catch { message.error('终止失败'); }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // CHANGE 2026-03-22 | 重新执行历史任务
  const handleRerun = useCallback(async (id: string) => {
    try {
      const { execution_id } = await rerunExecution(id);
      message.success(`已重新执行，新 ID: ${execution_id.slice(0, 8)}…`);
      load();
    } catch { message.error('重新执行失败'); }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const load = useCallback(async () => {
    setLoading(true);
    try { setData(await fetchHistory()); }
    catch { message.error('加载历史记录失败'); }
    finally { setLoading(false); }
  }, []);

  useEffect(() => { load(); }, [load]);

  /** 点击行时加载详情和日志；running 任务走 WebSocket 实时流 */
  const handleRowClick = useCallback(async (record: ExecutionLog) => {
    setDetail(record);
    setHistoryLogLines([]);
    setLogLoading(true);
    closeHistoryWs();

    if (record.status === 'running') {
      // running 任务：通过 WebSocket 实时推送日志
      const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
      const host = window.location.host;
      const ws = new WebSocket(`${protocol}//${host}/ws/logs/${record.id}`);
      historyWsRef.current = ws;

      ws.onopen = () => { setWsConnected(true); setLogLoading(false); };
      ws.onmessage = (event) => {
        setHistoryLogLines((prev) => [...prev, event.data]);
      };
      ws.onclose = () => {
        setWsConnected(false);
        // 任务结束后刷新历史列表以更新状态
        load();
      };
      ws.onerror = () => {
        message.error('WebSocket 连接失败，回退到静态日志');
        setWsConnected(false);
        // 回退：用 REST API 拉取已有日志
        apiClient.get<{
          execution_id: string;
          output_log: string | null;
          error_log: string | null;
        }>(`/execution/${record.id}/logs`).then(({ data: logData }) => {
          const parts: string[] = [];
          if (logData.output_log) parts.push(logData.output_log);
          if (logData.error_log) parts.push(logData.error_log);
          setHistoryLogLines(parts.join('\n').split('\n').filter(Boolean));
        }).catch(() => {}).finally(() => setLogLoading(false));
      };
    } else {
      // 已完成任务：REST API 一次性拉取
      try {
        const { data: logData } = await apiClient.get<{
          execution_id: string;
          output_log: string | null;
          error_log: string | null;
        }>(`/execution/${record.id}/logs`);
        const parts: string[] = [];
        if (logData.output_log) parts.push(logData.output_log);
        if (logData.error_log) parts.push(logData.error_log);
        setHistoryLogLines(parts.join('\n').split('\n').filter(Boolean));
      } catch {
        /* 日志可能不存在，静默处理 */
      } finally {
        setLogLoading(false);
      }
    }
  }, [closeHistoryWs, load]);

  // CHANGE 2026-03-27 | 支持 URL 参数 openExecution 自动打开任务详情
  const [searchParams, setSearchParams] = useSearchParams();
  const openExecutionHandled = useRef(false);
  useEffect(() => {
    const openId = searchParams.get('openExecution');
    if (!openId || openExecutionHandled.current || loading || data.length === 0) return;
    openExecutionHandled.current = true;
    const target = data.find((r) => r.id === openId);
    if (target) {
      handleRowClick(target);
    } else {
      handleRowClick({ id: openId, status: 'running' } as ExecutionLog);
    }
    searchParams.delete('openExecution');
    setSearchParams(searchParams, { replace: true });
  }, [data, loading, searchParams, setSearchParams, handleRowClick]);

  const columns: ColumnsType<ExecutionLog> = [
    {
      title: '执行 ID', dataIndex: 'id', key: 'id', width: 120,
      render: (id: string) => (
        <Text copyable={{ text: id }} style={{ fontSize: 11 }}>
          {id.slice(0, 8)}…
        </Text>
      ),
    },
    {
      title: '任务', dataIndex: 'task_codes', key: 'task_codes',
      render: (codes: string[]) => (
        <Text style={{ maxWidth: 300 }} ellipsis={{ tooltip: codes?.join(', ') }}>
          {codes?.join(', ') ?? '—'}
        </Text>
      ),
    },
    {
      title: '调度 ID', dataIndex: 'schedule_id', key: 'schedule_id', width: 120,
      render: (id: string | null) => id
        ? <Text copyable={{ text: id }} style={{ fontSize: 11 }}>{id.slice(0, 8)}…</Text>
        : '—',
    },
    {
      title: '状态', dataIndex: 'status', key: 'status', width: 90,
      render: (s: string) => <Tag color={STATUS_COLOR[s] ?? 'default'}>{s}</Tag>,
    },
    { title: '开始时间', dataIndex: 'started_at', key: 'started_at', width: 170, render: fmtTime },
    { title: '时长', dataIndex: 'duration_ms', key: 'duration_ms', width: 90, render: fmtDuration },
    {
      title: '退出码', dataIndex: 'exit_code', key: 'exit_code', width: 70, align: 'center',
      render: (v: number | null) => v != null ? (
        <Tag color={v === 0 ? 'success' : 'error'}>{v}</Tag>
      ) : '—',
    },
    {
      title: '操作', key: 'action', width: 140, align: 'center',
      render: (_: unknown, record: ExecutionLog) => (
        <Space size={0}>
          {record.status === 'running' && (
            <Popconfirm title="确认终止该任务？" onConfirm={(e) => { e?.stopPropagation(); handleCancelHistory(record.id); }} onCancel={(e) => e?.stopPropagation()}>
              <Button type="link" danger icon={<StopOutlined />} size="small" onClick={(e) => e.stopPropagation()}>
                终止
              </Button>
            </Popconfirm>
          )}
          {record.status !== 'running' && (
            <Popconfirm title="确认重新执行该任务？" onConfirm={(e) => { e?.stopPropagation(); handleRerun(record.id); }} onCancel={(e) => e?.stopPropagation()}>
              <Button type="link" icon={<PlayCircleOutlined />} size="small" onClick={(e) => e.stopPropagation()}>
                重新执行
              </Button>
            </Popconfirm>
          )}
        </Space>
      ),
    },
  ];

  return (
    <>
      <div style={{ marginBottom: 12, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <Text type="secondary">最近 {data.length} 条记录</Text>
        <Button icon={<ReloadOutlined />} onClick={load} loading={loading}>刷新</Button>
      </div>
      <Table<ExecutionLog>
        rowKey="id" columns={columns} dataSource={data}
        loading={loading} pagination={{ pageSize: 20, showTotal: (t) => `共 ${t} 条` }}
        size="small"
        onRow={(record) => ({ onClick: () => handleRowClick(record), style: { cursor: 'pointer' } })}
      />

      <Drawer
        title={
          <Space>
            <span>执行详情</span>
            {detail?.status === 'running' && (
              wsConnected
                ? <Tag color="processing">实时连接中</Tag>
                : <Tag>未连接</Tag>
            )}
          </Space>
        }
        open={!!detail}
        onClose={() => { closeHistoryWs(); setDetail(null); }}
        width={720}
        styles={{ body: { padding: 12 } }}
      >
        {detail && (
          <>
            <Descriptions column={1} bordered size="small" style={{ marginBottom: 16 }}>
              <Descriptions.Item label="任务">{detail.task_codes?.join(', ')}</Descriptions.Item>
              <Descriptions.Item label="状态">
                <Tag color={STATUS_COLOR[detail.status] ?? 'default'}>{detail.status}</Tag>
              </Descriptions.Item>
              <Descriptions.Item label="开始时间">{fmtTime(detail.started_at)}</Descriptions.Item>
              <Descriptions.Item label="结束时间">{fmtTime(detail.finished_at)}</Descriptions.Item>
              <Descriptions.Item label="时长">{fmtDuration(detail.duration_ms)}</Descriptions.Item>
              <Descriptions.Item label="退出码">
                {detail.exit_code != null ? (
                  <Tag color={detail.exit_code === 0 ? 'success' : 'error'}>{detail.exit_code}</Tag>
                ) : '—'}
              </Descriptions.Item>
              <Descriptions.Item label="命令">
                <code style={{ wordBreak: 'break-all', fontSize: 12 }}>{detail.command || '—'}</code>
              </Descriptions.Item>
            </Descriptions>

            {/* 历史日志展示 */}
            <div style={{ marginBottom: 8, display: 'flex', alignItems: 'center', gap: 8 }}>
              <FileTextOutlined />
              <Text strong>执行日志</Text>
              {logLoading && <Spin size="small" />}
            </div>
            <div style={{ height: 400 }}>
              <LogStream executionId={detail.id} lines={historyLogLines} />
            </div>
          </>
        )}
      </Drawer>
    </>
  );
};

/* ------------------------------------------------------------------ */
/*  主组件                                                             */
/* ------------------------------------------------------------------ */

const TaskManager: React.FC = () => {
  const items = [
    {
      key: 'queue',
      label: <Space><UnorderedListOutlined />队列</Space>,
      children: <QueueTab />,
    },
    {
      key: 'schedule',
      label: <Space><ClockCircleOutlined />调度</Space>,
      children: <ScheduleTab />,
    },
    {
      key: 'history',
      label: <Space><HistoryOutlined />历史</Space>,
      children: <HistoryTab />,
    },
  ];

  return (
    <div>
      <Title level={4} style={{ marginBottom: 16 }}>
        <UnorderedListOutlined style={{ marginRight: 8 }} />
        任务管理
      </Title>
      <Tabs defaultActiveKey="queue" items={items} />
    </div>
  );
};

export default TaskManager;
