"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import clsx from "clsx";
import ReactMarkdown from "react-markdown";
import Cropper from "react-easy-crop";

const apiBase = process.env.NEXT_PUBLIC_API_BASE || "/api";

type AssignmentSummary = {
  id: number;
  username: string;
  title: string;
  score: number;
  imagePath?: string;
  imagePaths?: string[];
  createdAt: string;
};

type AssignmentDetail = AssignmentSummary & {
  ocrText?: string;
  markdown: string;
  feedback: string;
  imagePath?: string;
  imagePaths?: string[];
};

type ImageItem = {
  id: string;
  name: string;
  file: Blob;
  previewUrl: string;
  croppedBlob?: Blob;
  croppedUrl?: string;
};

export default function HomePage() {
  const [username, setUsername] = useState("");
  const [savedUser, setSavedUser] = useState("");
  const [assignments, setAssignments] = useState<AssignmentSummary[]>([]);
  const [selectedId, setSelectedId] = useState<number | null>(null);
  const [selected, setSelected] = useState<AssignmentDetail | null>(null);

  const [title, setTitle] = useState("");
  const [images, setImages] = useState<ImageItem[]>([]);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [error, setError] = useState("");
  const [info, setInfo] = useState("");

  const videoRef = useRef<HTMLVideoElement>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const imagesRef = useRef<ImageItem[]>([]);

  const [cropTarget, setCropTarget] = useState<ImageItem | null>(null);
  const [crop, setCrop] = useState({ x: 0, y: 0 });
  const [zoom, setZoom] = useState(1);
  const [croppedAreaPixels, setCroppedAreaPixels] = useState<{
    x: number;
    y: number;
    width: number;
    height: number;
  } | null>(null);

  useEffect(() => {
    const stored = window.localStorage.getItem("hw_username");
    if (stored) {
      setUsername(stored);
      setSavedUser(stored);
      void loadAssignments(stored);
    }
    return () => {
      if (streamRef.current) {
        streamRef.current.getTracks().forEach((track) => track.stop());
      }
      imagesRef.current.forEach((item) => {
        URL.revokeObjectURL(item.previewUrl);
        if (item.croppedUrl) URL.revokeObjectURL(item.croppedUrl);
      });
    };
  }, []);

  useEffect(() => {
    imagesRef.current = images;
  }, [images]);

  const loadAssignments = async (user: string) => {
    setError("");
    try {
      const res = await fetch(`${apiBase}/assignments?username=${encodeURIComponent(user)}`);
      if (!res.ok) throw new Error("加载作业失败");
      const data = (await res.json()) as AssignmentSummary[];
      setAssignments(data);
      if (data.length > 0) {
        setSelectedId(data[0].id);
        await loadAssignmentDetail(data[0].id, user);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "加载失败");
    }
  };

  const loadAssignmentDetail = async (id: number, user = savedUser) => {
    setError("");
    try {
      const res = await fetch(
        `${apiBase}/assignments/${id}?username=${encodeURIComponent(user)}`
      );
      if (!res.ok) throw new Error("加载详情失败");
      const data = (await res.json()) as AssignmentDetail;
      setSelected(data);
    } catch (err) {
      setError(err instanceof Error ? err.message : "加载失败");
    }
  };

  const handleSaveUser = async () => {
    if (!username.trim()) return;
    const user = username.trim();
    setSavedUser(user);
    window.localStorage.setItem("hw_username", user);
    await loadAssignments(user);
  };

  const createId = () =>
    typeof crypto !== "undefined" && "randomUUID" in crypto
      ? crypto.randomUUID()
      : `${Date.now()}-${Math.random().toString(16).slice(2)}`;

  const revokeItemUrls = (item: ImageItem) => {
    URL.revokeObjectURL(item.previewUrl);
    if (item.croppedUrl) URL.revokeObjectURL(item.croppedUrl);
  };

  const createImageItem = (file: Blob, name: string): ImageItem => ({
    id: createId(),
    name,
    file,
    previewUrl: URL.createObjectURL(file),
  });

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setError("");
    const files = Array.from(event.target.files ?? []);
    if (files.length === 0) return;
    const newItems = files.map((file) =>
      createImageItem(file, file.name || `upload-${Date.now()}.png`)
    );
    setImages((prev) => [...prev, ...newItems]);
    setInfo(`已选择 ${files.length} 张图片，可继续追加上传。`);
    event.target.value = "";
  };

  const clearImages = () => {
    setImages((prev) => {
      prev.forEach(revokeItemUrls);
      return [];
    });
    setCropTarget(null);
    setCroppedAreaPixels(null);
  };

  const removeImage = (id: string) => {
    setImages((prev) => {
      const target = prev.find((item) => item.id === id);
      if (target) revokeItemUrls(target);
      return prev.filter((item) => item.id !== id);
    });
    if (cropTarget?.id === id) {
      setCropTarget(null);
      setCroppedAreaPixels(null);
    }
  };

  const onCropComplete = useCallback((_: unknown, areaPixels: any) => {
    setCroppedAreaPixels(areaPixels);
  }, []);

  const createImage = (url: string) =>
    new Promise<HTMLImageElement>((resolve, reject) => {
      const image = new Image();
      image.addEventListener("load", () => resolve(image));
      image.addEventListener("error", (err) => reject(err));
      image.setAttribute("crossOrigin", "anonymous");
      image.src = url;
    });

  const getCroppedImg = async (imageSrc: string, cropArea: { x: number; y: number; width: number; height: number }) => {
    const image = await createImage(imageSrc);
    const canvas = document.createElement("canvas");
    canvas.width = cropArea.width;
    canvas.height = cropArea.height;
    const ctx = canvas.getContext("2d");
    if (!ctx) throw new Error("Canvas not supported");

    ctx.drawImage(
      image,
      cropArea.x,
      cropArea.y,
      cropArea.width,
      cropArea.height,
      0,
      0,
      cropArea.width,
      cropArea.height
    );

    return new Promise<Blob>((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (!blob) {
          reject(new Error("Crop failed"));
          return;
        }
        resolve(blob);
      }, "image/png");
    });
  };

  const applyCrop = async () => {
    if (!cropTarget || !croppedAreaPixels) return;
    try {
      const blob = await getCroppedImg(cropTarget.previewUrl, croppedAreaPixels);
      const croppedUrl = URL.createObjectURL(blob);
      setImages((prev) =>
        prev.map((item) => {
          if (item.id !== cropTarget.id) return item;
          if (item.croppedUrl) URL.revokeObjectURL(item.croppedUrl);
          return { ...item, croppedBlob: blob, croppedUrl };
        })
      );
      setInfo("裁剪已应用，可直接提交或继续裁剪。");
    } catch {
      setError("裁剪失败，请重试");
    } finally {
      setCropTarget(null);
      setCroppedAreaPixels(null);
      setZoom(1);
      setCrop({ x: 0, y: 0 });
    }
  };

  const openCrop = (item: ImageItem) => {
    setCropTarget(item);
    setCrop({ x: 0, y: 0 });
    setZoom(1);
    setCroppedAreaPixels(null);
  };

  const restoreCrop = (id: string) => {
    setImages((prev) =>
      prev.map((item) => {
        if (item.id !== id) return item;
        if (item.croppedUrl) URL.revokeObjectURL(item.croppedUrl);
        return { ...item, croppedBlob: undefined, croppedUrl: undefined };
      })
    );
  };

  const startCamera = async () => {
    setError("");
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: "environment" },
      });
      streamRef.current = stream;
      if (videoRef.current) {
        videoRef.current.srcObject = stream;
        await videoRef.current.play();
      }
    } catch (err) {
      setError("无法打开摄像头，请检查权限设置");
    }
  };

  const capturePhoto = async () => {
    setError("");
    if (!videoRef.current) return;
    const video = videoRef.current;
    const canvas = document.createElement("canvas");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    const dataUrl = canvas.toDataURL("image/png");
    const blob = await (await fetch(dataUrl)).blob();
    const item = createImageItem(blob, `camera-${Date.now()}.png`);
    setImages((prev) => [...prev, item]);
    setInfo("拍照完成，可直接提交或继续拍照。");
  };

  const stopCamera = () => {
    if (streamRef.current) {
      streamRef.current.getTracks().forEach((track) => track.stop());
      streamRef.current = null;
    }
  };

  const handleSubmit = async () => {
    if (!savedUser) {
      setError("请先设置用户名");
      return;
    }
    if (images.length === 0) {
      setError("请先上传或拍照作业图片");
      return;
    }
    setError("");
    setIsSubmitting(true);
    setInfo("正在提交图片并调用 LLM 批改，请稍候...");
    try {
      const formData = new FormData();
      formData.append("username", savedUser);
      if (title.trim()) {
        formData.append("title", title.trim());
      }
      images.forEach((item, index) => {
        const blob = item.croppedBlob ?? item.file;
        const name = item.name || `page-${index + 1}.png`;
        formData.append("images", blob, name);
      });

      const res = await fetch(`${apiBase}/assignments`, {
        method: "POST",
        body: formData,
      });
      if (!res.ok) {
        const payload = await res.json().catch(() => ({}));
        throw new Error(payload.error || "提交失败");
      }
      const created = (await res.json()) as AssignmentDetail;
      setAssignments((prev) => [created, ...prev]);
      setSelectedId(created.id);
      setSelected(created);
      setTitle("");
      clearImages();
      setInfo("批改完成，可在右侧查看结果。");
    } catch (err) {
      setError(err instanceof Error ? err.message : "提交失败");
    } finally {
      setIsSubmitting(false);
    }
  };

  const handleDelete = async (id: number) => {
    if (!savedUser) return;
    try {
      const res = await fetch(
        `${apiBase}/assignments/${id}?username=${encodeURIComponent(savedUser)}`,
        { method: "DELETE" }
      );
      if (!res.ok) throw new Error("删除失败");
      setAssignments((prev) => prev.filter((item) => item.id !== id));
      if (selectedId === id) {
        setSelectedId(null);
        setSelected(null);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "删除失败");
    }
  };

  const imageUrlFor = (id: number, index = 0) =>
    `${apiBase}/assignments/${id}/image?username=${encodeURIComponent(savedUser)}&index=${index}`;

  const imageCountFor = (item: AssignmentSummary) =>
    item.imagePaths?.length ?? (item.imagePath ? 1 : 0);

  const selectedImagePaths =
    selected?.imagePaths && selected.imagePaths.length > 0
      ? selected.imagePaths
      : selected?.imagePath
      ? [selected.imagePath]
      : [];

  return (
    <main>
      <div className="page">
        <section className="hero">
          <div>
            <h1 className="hero-title">作业工坊</h1>
            <p>
              上传或拍照作业，直接交给 LLM 识别与批改，返回 Markdown 与反馈。
              前端无需登录，只需一个用户名即可管理自己的作业记录。
            </p>
          </div>
          <div className="stamp">Homework Atelier</div>
        </section>

        <section className="card">
          <header>
            <h2 className="section-title">我的身份</h2>
            <span className="tag">NO LOGIN REQUIRED</span>
          </header>
          <div className="username-card">
            <input
              className="input"
              placeholder="输入用户名（例如：小明）"
              value={username}
              onChange={(event) => setUsername(event.target.value)}
            />
            <button className="button" onClick={handleSaveUser}>
              开始管理
            </button>
            {savedUser && (
              <span className="muted">当前用户：{savedUser}</span>
            )}
          </div>
        </section>

        <section className="grid">
          <div className="card">
            <header>
              <h2 className="section-title">上传作业</h2>
              <span className="tag">IMAGE + LLM</span>
            </header>
            <div className="upload-area">
              <label className="muted">作业标题</label>
              <input
                className="input"
                placeholder="例如：数学作业 第5次"
                value={title}
                onChange={(event) => setTitle(event.target.value)}
              />

              <label className="muted">上传图片（支持多页）</label>
              <input type="file" accept="image/*" multiple onChange={handleFileChange} />
              <div className="muted">默认不裁剪，可选择“裁剪”后提交。</div>

              <div className="camera">
                <label className="muted">在线拍照</label>
                <video ref={videoRef} playsInline muted />
                <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                  <button className="button secondary" onClick={startCamera}>
                    打开摄像头
                  </button>
                  <button className="button" onClick={capturePhoto}>
                    拍照提交
                  </button>
                  <button className="button ghost" onClick={stopCamera}>
                    关闭摄像头
                  </button>
                </div>
              </div>

              {images.length > 0 && (
                <div className="thumbnail-grid">
                  {images.map((item, index) => (
                    <div key={item.id} className="thumb-card">
                      <img
                        className="preview"
                        src={item.croppedUrl ?? item.previewUrl}
                        alt={`第${index + 1}张`}
                      />
                      <div className="thumb-actions">
                        <span className="muted">第 {index + 1} 张</span>
                        <div className="thumb-buttons">
                          <button className="button secondary" onClick={() => openCrop(item)}>
                            裁剪
                          </button>
                          {item.croppedBlob && (
                            <button
                              className="button ghost"
                              onClick={() => restoreCrop(item.id)}
                            >
                              恢复原图
                            </button>
                          )}
                          <button className="button ghost" onClick={() => removeImage(item.id)}>
                            移除
                          </button>
                        </div>
                      </div>
                    </div>
                  ))}
                </div>
              )}

              {images.length > 0 && (
                <button className="button ghost" onClick={clearImages}>
                  清空图片
                </button>
              )}

              <button
                className="button"
                onClick={handleSubmit}
                disabled={isSubmitting}
              >
                {isSubmitting ? "批改中..." : "提交批改"}
              </button>

              {error && <div className="feedback">{error}</div>}
              {info && <div className="feedback">{info}</div>}
            </div>
          </div>

          <div className="card">
            <header>
              <h2 className="section-title">我的作业档案</h2>
              <span className="tag">HISTORY</span>
            </header>
            <div className="assignments">
              {assignments.length === 0 && (
                <div className="muted">暂无作业记录</div>
              )}
              {assignments.map((item) => (
                <div
                  key={item.id}
                  className={clsx("assignment-item", {
                    active: item.id === selectedId,
                  })}
                  onClick={async () => {
                    setSelectedId(item.id);
                    await loadAssignmentDetail(item.id);
                  }}
                >
                  <strong>{item.title}</strong>
                  <div className="assignment-meta">
                    <span>评分：{item.score || "-"}</span>
                    <span>{new Date(item.createdAt).toLocaleString()}</span>
                  </div>
                  <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginTop: 8 }}>
                    {imageCountFor(item) > 0 && (
                      <a
                        className="button secondary"
                        href={imageUrlFor(item.id, 0)}
                        download={`assignment-${item.id}-1.png`}
                        onClick={(event) => event.stopPropagation()}
                      >
                        保存图片{imageCountFor(item) > 1 ? ` (${imageCountFor(item)}张)` : ""}
                      </a>
                    )}
                    <button
                      className="button ghost"
                      onClick={(event) => {
                        event.stopPropagation();
                        void handleDelete(item.id);
                      }}
                    >
                      删除
                    </button>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </section>

        <section className="card">
          <header>
            <h2 className="section-title">批改结果</h2>
            <span className="tag">MARKDOWN</span>
          </header>
          {!selected && <div className="muted">选择一条作业查看详情</div>}
          {selected && (
            <div style={{ display: "grid", gap: 16 }}>
              <div className="assignment-meta">
                <span>标题：{selected.title}</span>
                <span>评分：{selected.score || "-"}</span>
              </div>
              {selectedImagePaths.length > 0 && (
                <div style={{ display: "grid", gap: 12 }}>
                  <div className="assignment-meta">
                    <span>原始图片（共 {selectedImagePaths.length} 张）</span>
                  </div>
                  <div className="image-grid">
                    {selectedImagePaths.map((_, index) => (
                      <div key={`${selected.id}-${index}`} className="image-card">
                        <img
                          className="preview"
                          src={imageUrlFor(selected.id, index)}
                          alt={`作业原图 ${index + 1}`}
                        />
                        <a
                          className="button secondary"
                          href={imageUrlFor(selected.id, index)}
                          download={`assignment-${selected.id}-${index + 1}.png`}
                        >
                          保存第 {index + 1} 张
                        </a>
                      </div>
                    ))}
                  </div>
                </div>
              )}
              <div className="markdown">
                <ReactMarkdown>{selected.markdown}</ReactMarkdown>
              </div>
              {selected.feedback && (
                <div className="feedback">
                  <strong>批改意见：</strong>
                  <div>{selected.feedback}</div>
                </div>
              )}
            </div>
          )}
        </section>
      </div>

      {cropTarget && (
        <div className="crop-overlay">
          <div className="crop-modal">
            <div className="crop-area">
              <Cropper
                image={cropTarget.previewUrl}
                crop={crop}
                zoom={zoom}
                aspect={4 / 3}
                onCropChange={setCrop}
                onZoomChange={setZoom}
                onCropComplete={onCropComplete}
              />
            </div>
            <div className="crop-controls">
              <label className="muted">缩放</label>
              <input
                type="range"
                min={1}
                max={3}
                step={0.05}
                value={zoom}
                onChange={(event) => setZoom(Number(event.target.value))}
              />
              <div className="crop-buttons">
                <button className="button secondary" onClick={applyCrop}>
                  应用裁剪
                </button>
                <button className="button ghost" onClick={() => setCropTarget(null)}>
                  取消
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </main>
  );
}
