import { useCallback, useEffect, useMemo, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { api } from "../api/client";

const TABLE_TYPES = [
  { id: "perechen", label: "Перечень" },
  { id: "specification_pcb", label: "Спец. ПП" },
  { id: "specification", label: "Спецификация" },
  { id: "vedomost", label: "Ведомость" },
  { id: "simple_list", label: "Бланк заказа" },
];

const COLUMNS = {
  perechen: [
    ["position", "Поз."],
    ["designation", "Наименование"],
    ["quantity", "Кол."],
    ["note", "Прим."],
  ],
  specification_pcb: [
    ["format", "Форм."],
    ["zone", "Зона"],
    ["position", "Поз."],
    ["designation", "Обозн."],
    ["name", "Наименование"],
    ["quantity", "Кол."],
    ["note", "Прим."],
  ],
  specification: [
    ["format", "Форм."],
    ["zone", "Зона"],
    ["position", "Поз."],
    ["designation", "Обозн."],
    ["name", "Наименование"],
    ["quantity", "Кол."],
    ["note", "Прим."],
  ],
  vedomost: [
    ["name", "Наименование"],
    ["product_code", "Код"],
    ["document_code", "Док."],
    ["supplier", "Поставщик"],
    ["where_used", "Куда"],
    ["quantity_per_item", "На изд."],
    ["total_quantity", "Всего"],
    ["note", "Прим."],
  ],
  simple_list: [
    ["designator", "Поз."],
    ["name", "Наименование"],
    ["quantity", "Кол."],
  ],
};

const FRAME_FIELDS = [
  [1, "Наименование изделия"],
  [2, "Обозначение документа"],
  [4, "Литера"],
  [9, "Организация"],
  [10, "Характер работы"],
  [11, "Фамилии"],
  [111, "Разработал"],
  [112, "Проверил"],
  [113, "Н. контроль"],
  [114, "Утвердил"],
  [251, "Перв. примен. (перечень)"],
  [252, "Перв. примен. (спец. ПП)"],
  [253, "Перв. примен. (спец.)"],
  [254, "Перв. примен. (ведомость)"],
  [301, "Наименование документа (ведомость)"],
  [1001, "Децимальный № (спец.)"],
  [1002, "Название документа (спец.)"],
];

const STATUS_LABELS = {
  created: "создан",
  parsing: "парсинг",
  ready: "готов",
  error: "ошибка",
};

function formatBytes(bytes) {
  if (!bytes) return "0 B";
  const units = ["B", "KB", "MB", "GB"];
  let value = bytes;
  let i = 0;
  while (value >= 1024 && i < units.length - 1) {
    value /= 1024;
    i += 1;
  }
  return `${value.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;
}

export default function ProjectPage() {
  const { id } = useParams();
  const projectId = Number(id);
  const [project, setProject] = useState(null);
  const [params, setParams] = useState([]);
  const [pcb, setPcb] = useState({ layer_count: 0, materials: [] });
  const [tableType, setTableType] = useState("perechen");
  const [rows, setRows] = useState([]);
  const [inscriptions, setInscriptions] = useState({});
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);
  const [chatInput, setChatInput] = useState("");
  const [chat, setChat] = useState([]);
  const [pendingEdits, setPendingEdits] = useState(null);
  const [tab, setTab] = useState("tables");
  const [uploadState, setUploadState] = useState(null);

  const uploading = uploadState && uploadState.phase !== "done";

  const loadProject = useCallback(async () => {
    const [p, par, pcbInfo, insc] = await Promise.all([
      api.getProject(projectId),
      api.getParams(projectId),
      api.getPcb(projectId),
      api.getInscriptions(projectId),
    ]);
    setProject(p);
    setParams(par);
    setPcb(pcbInfo);
    setInscriptions(insc || {});
  }, [projectId]);

  const loadTable = useCallback(async () => {
    const data = await api.getTable(projectId, tableType);
    setRows(data.rows || []);
  }, [projectId, tableType]);

  useEffect(() => {
    (async () => {
      try {
        setError("");
        await loadProject();
        await loadTable();
      } catch (e) {
        setError(e.message);
      }
    })();
  }, [loadProject, loadTable]);

  const columns = useMemo(() => COLUMNS[tableType] || [], [tableType]);

  async function onUpload(e, method = "POST") {
    const file = e.target.files?.[0];
    if (!file) return;
    setBusy(true);
    setError("");
    setUploadState({
      phase: "upload",
      percent: 0,
      loaded: 0,
      total: file.size,
      fileName: file.name,
      fileSize: file.size,
    });
    try {
      const updated = await api.uploadZip(projectId, file, method, true, setUploadState);
      setProject(updated);
      await Promise.all([loadProject(), loadTable()]);
      setUploadState({
        phase: "done",
        percent: 100,
        fileName: file.name,
        fileSize: file.size,
        loaded: file.size,
        total: file.size,
      });
      window.setTimeout(() => setUploadState(null), 4000);
    } catch (err) {
      setError(err.message);
      setUploadState(null);
    } finally {
      setBusy(false);
      e.target.value = "";
    }
  }

  async function saveMeta(patch) {
    setProject(await api.updateProject(projectId, patch));
  }

  async function generate() {
    setBusy(true);
    setError("");
    try {
      const data = await api.generateTable(projectId, tableType);
      setRows(data.rows || []);
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }

  async function saveRows() {
    setBusy(true);
    try {
      const data = await api.patchTable(projectId, tableType, rows);
      setRows(data.rows || []);
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }

  function updateCell(idx, field, value) {
    setRows((prev) => prev.map((r, i) => (i === idx ? { ...r, [field]: value } : r)));
  }

  async function saveInscriptions() {
    setBusy(true);
    try {
      const data = await api.patchInscriptions(projectId, inscriptions);
      setInscriptions(data);
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }

  async function sendChat() {
    if (!chatInput.trim()) return;
    const message = chatInput.trim();
    setChatInput("");
    setChat((c) => [...c, { role: "user", content: message }]);
    setBusy(true);
    try {
      const res = await api.llmChat(projectId, message, tableType);
      setChat((c) => [...c, { role: "assistant", content: res.reply, edits: res.edits }]);
      setPendingEdits(res.edits?.length ? res.edits : null);
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }

  async function applyEdits() {
    if (!pendingEdits?.length) return;
    setBusy(true);
    try {
      const data = await api.llmApply(projectId, tableType, pendingEdits);
      setRows(data.rows || []);
      setPendingEdits(null);
    } catch (e) {
      setError(e.message);
    } finally {
      setBusy(false);
    }
  }

  if (!project) {
    return <div className="card">{error || "Загрузка…"}</div>;
  }

  return (
    <div className="stack">
      <div className="card stack">
        <div className="row" style={{ justifyContent: "space-between" }}>
          <div>
            <Link to="/">← К списку</Link>
            <h2 style={{ margin: "0.4rem 0 0" }}>{project.name}</h2>
            <div className="muted">
              Статус:{" "}
              <span className={`status ${project.status}`}>
                {STATUS_LABELS[project.status] || project.status}
              </span>
              {project.error_message ? ` — ${project.error_message}` : ""}
            </div>
          </div>
          <div className="row">
            <label
              className="secondary"
              style={{
                background: uploading ? "#8a9690" : "#4a5a53",
                color: "#fff",
                padding: "0.45rem 0.85rem",
                borderRadius: 6,
                cursor: uploading ? "not-allowed" : "pointer",
              }}
            >
              Загрузить ZIP
              <input type="file" accept=".zip" hidden disabled={uploading} onChange={(e) => onUpload(e, "POST")} />
            </label>
            <label
              className="secondary"
              style={{
                background: uploading ? "#8a9690" : "#4a5a53",
                color: "#fff",
                padding: "0.45rem 0.85rem",
                borderRadius: 6,
                cursor: uploading ? "not-allowed" : "pointer",
              }}
            >
              Обновить ZIP
              <input type="file" accept=".zip" hidden disabled={uploading} onChange={(e) => onUpload(e, "PUT")} />
            </label>
          </div>
        </div>

        {uploadState && (
          <div
            className={`upload-panel ${uploadState.phase === "processing" ? "processing" : ""} ${
              uploadState.phase === "done" ? "done" : ""
            }`}
          >
            <strong>
              {uploadState.phase === "upload" && "Загрузка архива на сервер…"}
              {uploadState.phase === "processing" && "Файл загружен, идёт распаковка и парсинг…"}
              {uploadState.phase === "done" && "Проект успешно загружен"}
            </strong>
            <div className="muted">
              {uploadState.fileName} ({formatBytes(uploadState.fileSize)})
              {uploadState.phase === "upload" &&
                ` — ${formatBytes(uploadState.loaded)} / ${formatBytes(uploadState.total)}`}
            </div>
            {uploadState.phase !== "done" ? (
              <div className={`progress ${uploadState.phase === "processing" ? "indeterminate" : ""}`}>
                <span style={{ width: `${uploadState.percent || 0}%` }} />
              </div>
            ) : null}
            {uploadState.phase === "upload" && (
              <div className="muted">{uploadState.percent ?? 0}%</div>
            )}
            {uploadState.phase === "processing" && (
              <div className="muted">Это может занять несколько минут для больших архивов.</div>
            )}
          </div>
        )}

        <div className="row">
          <label>Вариант</label>
          <select
            value={project.current_variant}
            onChange={(e) => saveMeta({ current_variant: e.target.value })}
          >
            {(project.variants?.length ? project.variants : ["No Variations"]).map((v) => (
              <option key={v} value={v}>
                {v}
              </option>
            ))}
          </select>
          <label>Децимальный №</label>
          <input
            value={project.decimal_number || ""}
            onChange={(e) => setProject({ ...project, decimal_number: e.target.value })}
            onBlur={(e) => saveMeta({ decimal_number: e.target.value })}
          />
          <label>Название платы</label>
          <input
            value={project.board_name || ""}
            onChange={(e) => setProject({ ...project, board_name: e.target.value })}
            onBlur={(e) => saveMeta({ board_name: e.target.value })}
          />
        </div>

        <div className="muted">
          Компонентов: {project.component_count}, слоёв PCB: {project.layer_count}
          {project.pcb_doc_name ? `, файл: ${project.pcb_doc_name}` : ""}
        </div>
        {error && <div className="error">{error}</div>}
      </div>

      <div className="tabs">
        <button className={`tab ${tab === "tables" ? "active" : ""}`} onClick={() => setTab("tables")}>
          Таблицы
        </button>
        <button className={`tab ${tab === "frame" ? "active" : ""}`} onClick={() => setTab("frame")}>
          Рамка
        </button>
        <button className={`tab ${tab === "info" ? "active" : ""}`} onClick={() => setTab("info")}>
          Инфо проекта
        </button>
      </div>

      {tab === "info" && (
        <div className="grid two">
          <div className="card">
            <h3>Параметры проекта</h3>
            <div className="table-wrap">
              <table className="data">
                <thead>
                  <tr>
                    <th>Имя</th>
                    <th>Значение</th>
                  </tr>
                </thead>
                <tbody>
                  {params.map((p) => (
                    <tr key={p.id}>
                      <td>{p.name}</td>
                      <td>{p.value}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
          <div className="card">
            <h3>PCB / диэлектрики</h3>
            <p className="muted">Слоёв: {pcb.layer_count}</p>
            <div className="table-wrap">
              <table className="data">
                <thead>
                  <tr>
                    <th>Слой</th>
                    <th>Тип</th>
                    <th>Материал</th>
                    <th>мм</th>
                  </tr>
                </thead>
                <tbody>
                  {pcb.materials?.map((m, i) => (
                    <tr key={i}>
                      <td>{m.layer_number}</td>
                      <td>{m.diel_type === 1 ? "ядро" : "препрег"}</td>
                      <td>{m.value}</td>
                      <td>{m.height?.toFixed?.(3)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      )}

      {tab === "frame" && (
        <div className="card stack">
          <h3>Поля основной надписи</h3>
          <div className="grid" style={{ gridTemplateColumns: "repeat(auto-fill,minmax(280px,1fr))" }}>
            {FRAME_FIELDS.map(([num, label]) => (
              <label key={num} className="stack">
                <span className="muted">
                  {num}. {label}
                </span>
                <input
                  value={inscriptions[num] || inscriptions[String(num)] || ""}
                  onChange={(e) =>
                    setInscriptions((prev) => ({ ...prev, [num]: e.target.value }))
                  }
                />
              </label>
            ))}
          </div>
          <div>
            <button disabled={busy} onClick={saveInscriptions}>
              Сохранить рамку
            </button>
          </div>
        </div>
      )}

      {tab === "tables" && (
        <div className="grid two">
          <div className="card stack">
            <div className="tabs">
              {TABLE_TYPES.map((t) => (
                <button
                  key={t.id}
                  className={`tab ${tableType === t.id ? "active" : ""}`}
                  onClick={() => setTableType(t.id)}
                >
                  {t.label}
                </button>
              ))}
            </div>
            <div className="row">
              <button disabled={busy} onClick={generate}>
                Сгенерировать
              </button>
              <button disabled={busy} className="secondary" onClick={saveRows}>
                Сохранить строки
              </button>
              <button disabled={busy} onClick={() => api.exportDoc(projectId, tableType, "xlsx")}>
                Excel
              </button>
              {tableType !== "simple_list" && (
                <button disabled={busy} onClick={() => api.exportDoc(projectId, tableType, "pdf")}>
                  PDF
                </button>
              )}
            </div>
            <div className="table-wrap">
              <table className="data">
                <thead>
                  <tr>
                    <th>#</th>
                    {columns.map(([key, label]) => (
                      <th key={key}>{label}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {rows.map((row, idx) => (
                    <tr key={row.id || idx} className={row.is_header ? "header-row" : ""}>
                      <td className="muted">{row.row_index ?? idx}</td>
                      {columns.map(([key]) => (
                        <td key={key}>
                          <input
                            value={row[key] ?? ""}
                            disabled={row.is_empty}
                            onChange={(e) => updateCell(idx, key, e.target.value)}
                          />
                        </td>
                      ))}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          <div className="card stack">
            <h3>LLM-помощник</h3>
            <p className="muted">Команды вроде «добавь примечание к R1». Правки применяются только после подтверждения.</p>
            <div className="chat">
              {chat.map((m, i) => (
                <div key={i} className={`bubble ${m.role}`}>
                  {m.content}
                  {m.edits?.length ? (
                    <div className="edits" style={{ marginTop: 6 }}>
                      Предложено правок: {m.edits.length}
                    </div>
                  ) : null}
                </div>
              ))}
            </div>
            {pendingEdits?.length ? (
              <div className="edits stack">
                <strong>Ожидают применения: {pendingEdits.length}</strong>
                <pre style={{ margin: 0, whiteSpace: "pre-wrap" }}>
                  {JSON.stringify(pendingEdits, null, 2)}
                </pre>
                <div className="row">
                  <button disabled={busy} onClick={applyEdits}>
                    Применить
                  </button>
                  <button className="secondary" onClick={() => setPendingEdits(null)}>
                    Отклонить
                  </button>
                </div>
              </div>
            ) : null}
            <div className="row">
              <input
                style={{ flex: 1 }}
                value={chatInput}
                placeholder="Сообщение…"
                onChange={(e) => setChatInput(e.target.value)}
                onKeyDown={(e) => e.key === "Enter" && sendChat()}
              />
              <button disabled={busy} onClick={sendChat}>
                Отправить
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
