import { useEffect, useState, useRef, useCallback } from "react";
import { useParams, useNavigate } from "react-router-dom";
import {
  Layout, Button, Modal, Form, Input, Select,
  Space, message, Spin, Popconfirm, Card, Switch,
} from "antd";
import {
  PlusOutlined, DeleteOutlined, EditOutlined, SaveOutlined,
  ArrowLeftOutlined, ThunderboltOutlined, DownloadOutlined,
  ExperimentOutlined, MenuFoldOutlined, MenuUnfoldOutlined,
  MenuOutlined, PaperClipOutlined,
} from "@ant-design/icons";
import { Editor } from "@tinymce/tinymce-react";
import type { Editor as TinyMCEEditor } from "tinymce";
import type { GenerationPoint, AIModel } from "../types";
import * as templateApi from "../api/templates";
import * as pointApi from "../api/generationPoints";
import * as modelApi from "../api/models";
import request from "../api/request";
import GenerateModal from "../components/GenerateModal";

const { Sider, Content } = Layout;

export default function TemplateEditor() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const editorRef = useRef<TinyMCEEditor | null>(null);
  const selectionRef = useRef<{ start: number; end: number; text: string } | null>(null);

  const [htmlContent, setHtmlContent] = useState("");
  const [templateName, setTemplateName] = useState("");
  const [points, setPoints] = useState<GenerationPoint[]>([]);
  const [models, setModels] = useState<AIModel[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [pointModalOpen, setPointModalOpen] = useState(false);
  const [editingPoint, setEditingPoint] = useState<GenerationPoint | null>(null);
  const [showSelectionBtn, setShowSelectionBtn] = useState(false);
  const [selBtnPos, setSelBtnPos] = useState({ x: 0, y: 0 });
  const [pointForm] = Form.useForm();
  const [panelCollapsed, setPanelCollapsed] = useState(false);
  const [generateModalOpen, setGenerateModalOpen] = useState(false);

  const dragItem = useRef<number | null>(null);
  const dragOverItem = useRef<number | null>(null);

  const loadData = useCallback(async () => {
    if (!id) return;
    setLoading(true);
    try {
      const [template, pointsData, modelsData] = await Promise.all([
        templateApi.getTemplate(id),
        pointApi.listGenerationPoints(id),
        modelApi.listModels({ enabled: true }),
      ]);
      setTemplateName(template.name);
      setHtmlContent(template.html_content || "");
      setPoints(pointsData);
      setModels(modelsData);
    } catch {
      message.error("加载数据失败");
    } finally {
      setLoading(false);
    }
  }, [id]);

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

  const handleSave = async () => {
    if (!id) return;
    setSaving(true);
    try {
      const html = editorRef.current?.getContent() || htmlContent;
      await templateApi.updateTemplateHtml(id, html);
      setHtmlContent(html);
      message.success("保存成功");
    } catch {
      message.error("保存失败");
    } finally {
      setSaving(false);
    }
  };

  const handleEditorInit = (_evt: unknown, editor: TinyMCEEditor) => {
    editorRef.current = editor;
    editor.on("selectionchange", () => {
      const sel = editor.selection.getContent({ format: "text" });
      if (sel && sel.trim().length > 0) {
        const content = editor.getContent();
        const rng = editor.selection.getRng();
        if (rng) {
          const preRange = rng.cloneRange();
          preRange.selectNodeContents(editor.getBody());
          preRange.setEnd(rng.startContainer, rng.startOffset);
          const start = preRange.toString().length;
          const end = start + sel.length;
          selectionRef.current = { start, end, text: sel.trim() };
        }
        const ed = editor.getContainer();
        const rect = ed.getBoundingClientRect();
        setSelBtnPos({ x: rect.left + 100, y: rect.top + 10 });
        setShowSelectionBtn(true);
      } else {
        setShowSelectionBtn(false);
      }
    });
  };

  const handleCreatePoint = () => {
    setEditingPoint(null);
    setPointModalOpen(true);
  };

  const handleEditPoint = (point: GenerationPoint) => {
    setEditingPoint(point);
    setPointModalOpen(true);
  };

  useEffect(() => {
    if (!pointModalOpen) return;
    const timer = setTimeout(() => {
      if (editingPoint) {
        pointForm.setFieldsValue({
          prompt: editingPoint.prompt,
          model_id: editingPoint.model_id,
          need_ref_file: editingPoint.need_ref_file,
          remark: editingPoint.remark,
        });
      } else {
        pointForm.resetFields();
        if (selectionRef.current) {
          pointForm.setFieldsValue({
            prompt: `根据上下文生成关于「${selectionRef.current.text.slice(0, 20)}...」的内容`,
          });
        }
      }
    }, 0);
    return () => clearTimeout(timer);
  }, [pointModalOpen]);

  const handlePointSubmit = async () => {
    if (!id) return;
    try {
      const values = await pointForm.validateFields();
      const position = selectionRef.current
        ? { start: selectionRef.current.start, end: selectionRef.current.end }
        : editingPoint?.position;

      if (editingPoint) {
        const updateData: Record<string, unknown> = {};
        if (values.prompt) updateData.prompt = values.prompt;
        if (values.model_id) updateData.model_id = values.model_id;
        updateData.need_ref_file = values.need_ref_file || false;
        if (values.remark !== undefined) updateData.remark = values.remark;
        await pointApi.updateGenerationPoint(editingPoint.id, updateData);
        message.success("更新成功");
      } else if (position) {
        await pointApi.createGenerationPoint({
          template_id: id,
          position: JSON.stringify(position),
          prompt: values.prompt,
          model_id: values.model_id,
          order: points.length,
          selected_text: selectionRef.current?.text,
          need_ref_file: values.need_ref_file || false,
          remark: values.remark || "",
        });
        message.success("创建成功");
        selectionRef.current = null;
        setShowSelectionBtn(false);
      } else {
        message.warning("请先在编辑器中选中文本");
        return;
      }

      setPointModalOpen(false);
      const updated = await pointApi.listGenerationPoints(id);
      setPoints(updated);
    } catch (err: unknown) {
      if (err instanceof Error) message.error(err.message);
    }
  };

  const handleDeletePoint = async (pointId: string) => {
    await pointApi.deleteGenerationPoint(pointId);
    message.success("删除成功");
    const updated = await pointApi.listGenerationPoints(id!);
    setPoints(updated);
  };

  const handleDragStart = (_e: React.DragEvent, index: number) => {
    dragItem.current = index;
  };

  const handleDragEnter = (_e: React.DragEvent, index: number) => {
    dragOverItem.current = index;
  };

  const handleDragEnd = async () => {
    if (dragItem.current === null || dragOverItem.current === null) return;
    if (dragItem.current === dragOverItem.current) return;

    const newPoints = [...points];
    const [moved] = newPoints.splice(dragItem.current, 1);
    newPoints.splice(dragOverItem.current!, 0, moved);

    const reordered = newPoints.map((p, i) => ({ ...p, order: i }));
    setPoints(reordered);

    try {
      await pointApi.batchUpdateOrder(
        reordered.map((p) => ({ id: p.id, order: p.order }))
      );
    } catch {
      message.error("排序更新失败");
    }

    dragItem.current = null;
    dragOverItem.current = null;
  };

  const handleTestPoint = async (pointId: string) => {
    const point = points.find((p) => p.id === pointId);
    if (!point) return;

    if (point.need_ref_file) {
      const fileInput = document.createElement("input");
      fileInput.type = "file";
      fileInput.multiple = true;
      fileInput.accept = ".txt,.docx,.pdf";
      fileInput.onchange = async (e: Event) => {
        const files = (e.target as HTMLInputElement).files;
        if (!files || files.length === 0) return;
        try {
          message.loading({ content: "测试中...", key: "test" });
          const formData = new FormData();
          Array.from(files).forEach((f) => formData.append("ref_files", f));
          const { default: request } = await import("../api/request");
          const { data } = await request.post<{ result: string }>(
            `/generation-points/${pointId}/test`,
            formData
          );
          message.success({ content: "测试完成", key: "test" });
          Modal.info({ title: "AI 生成结果", content: data.result, width: 600 });
        } catch {
          message.error({ content: "测试失败", key: "test" });
        }
      };
      fileInput.click();
      return;
    }

    try {
      message.loading({ content: "测试中...", key: "test" });
      const result = await pointApi.testGenerationPoint(pointId);
      message.success({ content: "测试完成", key: "test" });
      Modal.info({ title: "AI 生成结果", content: result, width: 600 });
    } catch {
      message.error({ content: "测试失败", key: "test" });
    }
  };

  const handleGenerate = () => {
    if (!id) return;
    if (points.length === 0) {
      message.warning("请先添加至少一个生成点");
      return;
    }
    setGenerateModalOpen(true);
  };

  if (loading) {
    return (
      <div style={{ textAlign: "center", padding: 100 }}>
        <Spin size="large" />
      </div>
    );
  }

  return (
    <div style={{ height: "calc(100vh - 120px)" }}>
      <div
        style={{
          marginBottom: 12,
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
        }}
      >
        <Space>
          <Button icon={<ArrowLeftOutlined />} onClick={() => navigate("/templates")}>
            返回
          </Button>
          <h3 style={{ margin: 0 }}>{templateName}</h3>
        </Space>
        <Space>
          <Button
            icon={panelCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
            onClick={() => setPanelCollapsed(!panelCollapsed)}
          />
          <Button icon={<SaveOutlined />} onClick={handleSave} loading={saving}>
            保存
          </Button>
          <Button
            type="primary"
            danger
            icon={<ThunderboltOutlined />}
            onClick={handleGenerate}
          >
            生成文档
          </Button>
        </Space>
      </div>
      <Layout style={{ height: "calc(100% - 50px)", background: "#fff" }}>
        <Content style={{ position: "relative", overflow: "hidden" }}>
          {showSelectionBtn && (
            <div style={{
              position: "absolute",
              zIndex: 1310,
              top: 0,
              right: 8,
              padding: "4px 8px",
              background: "#fff",
              borderRadius: "0 0 4px 4px",
              boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
            }}>
              <Button
                type="primary"
                size="small"
                icon={<PlusOutlined />}
                onClick={handleCreatePoint}
              >
                设为 AI 生成点
              </Button>
            </div>
          )}
          <Editor
            key={id}
            tinymceScriptSrc="/tinymce/tinymce.min.js"
            initialValue={htmlContent}
            onInit={handleEditorInit}
            init={{
              height: "100%",
              menubar: true,
              license_key: "gpl",
              plugins: [
                "advlist", "autolink", "lists", "link", "image",
                "charmap", "preview", "anchor", "searchreplace",
                "visualblocks", "code", "fullscreen", "insertdatetime",
                "media", "table", "help", "wordcount",
              ],
              toolbar:
                "undo redo | blocks | bold italic forecolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help",
              content_style: "body { font-family: Arial, sans-serif; font-size: 14px; }",
            }}
            }}
          />
        </Content>
        {!panelCollapsed && (
          <Sider width={320} theme="light" style={{ padding: 16, overflow: "auto", borderLeft: "1px solid #f0f0f0" }}>
            <h4 style={{ marginBottom: 12 }}>生成点列表 ({points.length})</h4>
            {points.map((point, index) => {
              const model = models.find((m) => m.id === point.model_id);
              return (
                <div
                  key={point.id}
                  draggable
                  onDragStart={(e) => handleDragStart(e, index)}
                  onDragEnter={(e) => handleDragEnter(e, index)}
                  onDragEnd={handleDragEnd}
                  onDragOver={(e) => e.preventDefault()}
                  style={{ marginBottom: 8, cursor: "grab" }}
                >
                  <Card
                    size="small"
                    title={
                      <Space size={4}>
                        <MenuOutlined style={{ color: "#bbb", fontSize: 12, cursor: "grab" }} />
                        <span style={{ fontSize: 12, color: "#999" }}>#{index + 1}</span>
                        {model && (
                          <span style={{ fontSize: 12, color: "#1677ff" }}>
                            {model.name}
                          </span>
                        )}
                      </Space>
                    }
                    extra={
                      <Space size={4}>
                        {point.need_ref_file && (
                          <Button
                            type="text"
                            size="small"
                            icon={<PaperClipOutlined />}
                            onClick={async () => {
                              const input = document.createElement("input");
                              input.type = "file";
                              input.multiple = true;
                              input.accept = ".txt,.docx,.pdf";
                              input.onchange = async (e) => {
                                const files = (e.target as HTMLInputElement).files;
                                if (!files?.length) return;
                                const fd = new FormData();
                                Array.from(files).forEach((f) => fd.append("ref_files", f));
                                await request.post(`/generation-points/${point.id}/upload-ref`, fd);
                                message.success("上传成功");
                                const updated = await pointApi.listGenerationPoints(id!);
                                setPoints(updated);
                              };
                              input.click();
                            }}
                          />
                        )}
                        <Button
                          type="text"
                          size="small"
                          icon={<ExperimentOutlined />}
                          onClick={() => handleTestPoint(point.id)}
                        />
                        <Button
                          type="text"
                          size="small"
                          icon={<EditOutlined />}
                          onClick={() => handleEditPoint(point)}
                        />
                        <Popconfirm
                          title="确定删除？"
                          onConfirm={() => handleDeletePoint(point.id)}
                        >
                          <Button type="text" size="small" danger icon={<DeleteOutlined />} />
                        </Popconfirm>
                      </Space>
                    }
                  >
                    <p style={{ fontSize: 12, color: "#666", margin: 0, wordBreak: "break-all" }}>
                      {point.prompt.slice(0, 80)}
                      {point.prompt.length > 80 && "..."}
                    </p>
                  </Card>
                </div>
              );
            })}
            {points.length === 0 && (
              <p style={{ color: "#999", fontSize: 13 }}>
                选中编辑器中的文本，点击"设为 AI 生成点"
              </p>
            )}
          </Sider>
        )}
      </Layout>

      <Modal
        title={editingPoint ? "编辑生成点" : "新建生成点"}
        open={pointModalOpen}
        onCancel={() => { setPointModalOpen(false); pointForm.resetFields(); }}
        onOk={handlePointSubmit}
        width={560}
      >
        <Form form={pointForm} layout="vertical">
          {selectionRef.current && !editingPoint && (
            <div
              style={{
                marginBottom: 12,
                padding: 8,
                background: "#f6f8fa",
                borderRadius: 6,
                fontSize: 13,
                color: "#666",
              }}
            >
              已选中: 「{selectionRef.current.text.slice(0, 50)}
              {selectionRef.current.text.length > 50 ? "..." : ""}」
            </div>
          )}
          <Form.Item name="prompt" label="提示词" rules={[{ required: true }]}>
            <Input.TextArea
              rows={4}
              placeholder="请输入 AI 生成提示词，例如：请根据参考文件内容，生成一段项目背景介绍..."
            />
          </Form.Item>
          <Form.Item name="model_id" label="AI 模型">
            <Select
              allowClear
              placeholder="留空则使用全局默认模型"
              options={models.map((m) => ({ label: m.name, value: m.id }))}
            />
          </Form.Item>
          <Form.Item name="need_ref_file" label="需要参考文件" valuePropName="checked">
            <Switch />
          </Form.Item>
          <Form.Item name="remark" label="备注">
            <Input.TextArea rows={2} placeholder="补充说明（可选）" />
          </Form.Item>
        </Form>
      </Modal>

      <GenerateModal
        open={generateModalOpen}
        onClose={() => setGenerateModalOpen(false)}
        templateId={id || ""}
        points={points}
        models={models}
      />
    </div>
  );
}
