"use client";

import Link from "next/link";
import Image from "next/image";
import { FormEvent, useCallback, useEffect, useState } from "react";
import { BookIcon, UploadIcon } from "@/components/AppBrand";
import { apiJson } from "@/lib/client/http";
import { DEFAULT_EDGE_VOICES } from "@/lib/client/tts/edge-browser";

interface Book {
  id: string;
  title: string;
  author: string;
  format: "epub" | "pdf";
  coverUrl: string | null;
  progress: {
    chapterTitle: string;
    chapterPosition: number;
    segmentPosition: number;
    percent: number;
    updatedAt: string;
  } | null;
  status: "uploading" | "processing" | "ready" | "partial" | "failed";
  statusDetail: string | null;
  preferredZhVoice: string | null;
  preferredEnVoice: string | null;
  preferredRate: number | null;
  lastListenedAt: string | null;
  createdAt: string;
}

interface StorageUsage {
  usedBytes: number;
  sourceBytes: number;
  audioBytes: number;
  pendingUploadBytes: number;
  softLimitBytes: number;
}

const statusText: Record<Book["status"], string> = {
  uploading: "上传中",
  processing: "等待解析",
  ready: "可以收听",
  partial: "可以试听 · 尚未完成",
  failed: "处理失败",
};

const voiceOptions = {
  zh: [
    ["zh-CN-XiaoxiaoNeural", "晓晓 · 女声"],
    ["zh-CN-YunxiNeural", "云希 · 男声"],
    ["zh-CN-XiaoyiNeural", "晓伊 · 女声"],
  ],
  en: [
    ["en-US-AriaNeural", "Aria · 女声"],
    ["en-US-GuyNeural", "Guy · 男声"],
    ["en-US-JennyNeural", "Jenny · 女声"],
  ],
};

function formatBytes(bytes: number): string {
  if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB`;
  if (bytes < 1024 ** 3) return `${(bytes / 1024 ** 2).toFixed(1)} MB`;
  return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
}

export function LibraryView() {
  const [books, setBooks] = useState<Book[]>([]);
  const [storage, setStorage] = useState<StorageUsage | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [query, setQuery] = useState("");
  const [editing, setEditing] = useState<Book | null>(null);
  const [deleting, setDeleting] = useState<Book | null>(null);
  const [working, setWorking] = useState(false);

  const load = useCallback(async (search = "") => {
    setLoading(true);
    setError("");
    try {
      const [bookResult, storageResult] = await Promise.all([
        apiJson<{ books: Book[] }>(`/api/books${search ? `?q=${encodeURIComponent(search)}` : ""}`),
        apiJson<{ storage: StorageUsage }>("/api/storage"),
      ]);
      setBooks(bookResult.books);
      setStorage(storageResult.storage);
    } catch (loadError) {
      setError(loadError instanceof Error ? loadError.message : "书架暂时无法加载。");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    let active = true;
    void Promise.all([
      apiJson<{ books: Book[] }>("/api/books"),
      apiJson<{ storage: StorageUsage }>("/api/storage"),
    ]).then(([bookResult, storageResult]) => {
      if (!active) return;
      setBooks(bookResult.books);
      setStorage(storageResult.storage);
    }).catch((cause: unknown) => {
      if (active) setError(cause instanceof Error ? cause.message : "书架暂时无法加载。");
    }).finally(() => {
      if (active) setLoading(false);
    });
    return () => { active = false; };
  }, []);

  async function submitSearch(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    const search = String(data.get("q") || data.get("mobileQuery") || query).trim();
    setQuery(search);
    await load(search);
  }

  async function saveMetadata(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!editing) return;
    setWorking(true);
    setError("");
    try {
      const data = new FormData(event.currentTarget);
      let result = await apiJson<{ book: Book }>(`/api/books/${editing.id}`, {
        method: "PATCH",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          title: String(data.get("title") ?? ""),
          author: String(data.get("author") ?? ""),
          preferredZhVoice: String(data.get("preferredZhVoice") || DEFAULT_EDGE_VOICES["zh-CN"]),
          preferredEnVoice: String(data.get("preferredEnVoice") || DEFAULT_EDGE_VOICES["en-US"]),
          preferredRate: Number(data.get("preferredRate") || 1),
        }),
      });
      const cover = data.get("cover");
      if (cover instanceof File && cover.size > 0) {
        result = await apiJson<{ book: Book }>(`/api/books/${editing.id}/cover`, {
          method: "PUT",
          headers: { "content-type": cover.type },
          body: cover,
        });
      }
      setBooks((values) => values.map((book) => book.id === result.book.id ? result.book : book));
      setEditing(null);
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : "书籍信息保存失败。");
    } finally {
      setWorking(false);
    }
  }

  async function removeCover() {
    if (!editing?.coverUrl) return;
    setWorking(true);
    setError("");
    try {
      const result = await apiJson<{ book: Book }>(`/api/books/${editing.id}/cover`, {
        method: "DELETE",
      });
      setBooks((values) => values.map((book) => book.id === result.book.id ? result.book : book));
      setEditing(result.book);
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : "封面移除失败。");
    } finally {
      setWorking(false);
    }
  }

  async function deleteBook() {
    if (!deleting) return;
    setWorking(true);
    setError("");
    try {
      await apiJson(`/api/books/${deleting.id}`, {
        method: "DELETE",
        headers: { "x-confirm-delete": "DELETE" },
      });
      setBooks((values) => values.filter((book) => book.id !== deleting.id));
      setDeleting(null);
      const result = await apiJson<{ storage: StorageUsage }>("/api/storage");
      setStorage(result.storage);
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : "书籍删除失败。");
    } finally {
      setWorking(false);
    }
  }

  return (
    <main className="library-main">
      <section className="library-heading">
        <div><p className="eyebrow">你的私人收听空间</p><h1>我的书架</h1><p>最近收听的书会排在最前面。</p></div>
        <div className="library-meta" aria-label="书架统计">
          <span><strong>{books.length}</strong> 本书</span>
          <span title={storage ? `源文件 ${formatBytes(storage.sourceBytes)} · 音频 ${formatBytes(storage.audioBytes)}` : undefined}>
            <strong>{storage ? formatBytes(storage.usedBytes) : "—"}</strong> / 8 GB
          </span>
        </div>
      </section>

      <form id="library-search-form" className="mobile-search" onSubmit={submitSearch}>
        <label><span className="sr-only">搜索书名或作者</span><input name="mobileQuery" value={query} onChange={(event) => setQuery(event.target.value)} placeholder="搜索书名或作者" /></label>
        <button className="button" type="submit">搜索</button>
      </form>

      {loading ? (
        <section className="state-card" role="status"><span className="loading-dot" />正在打开书架…</section>
      ) : error && !books.length ? (
        <section className="state-card state-error" role="alert"><strong>书架没有打开</strong><p>{error}</p><button className="button" onClick={() => void load(query)}>重试</button></section>
      ) : books.length ? (
        <section className="book-grid" aria-label="书籍列表">
          {books.map((book) => (
            <article className="book-card" key={book.id}>
              <Link className="book-cover" href={book.status === "processing" ? `/books/${book.id}/edit` : `/books/${book.id}/listen`}>
                {book.coverUrl ? <Image src={book.coverUrl} alt="" fill sizes="(max-width: 760px) 45vw, 220px" unoptimized /> : <BookIcon />}
                <span className={`book-status status-${book.status}`}>{statusText[book.status]}</span>
              </Link>
              <div className="book-card-copy">
                <span className="format-chip">{book.format.toUpperCase()}</span>
                <h2><Link href={`/books/${book.id}/listen`}>{book.title}</Link></h2><p>{book.author}</p>
                {book.progress ? <div className="book-progress" aria-label={`收听进度 ${book.progress.percent}%`}>
                  <span><em>{book.progress.chapterTitle}</em><strong>{book.progress.percent}%</strong></span>
                  <progress value={book.progress.percent} max="100">{book.progress.percent}%</progress>
                </div> : <p className="book-progress-empty">还没有开始收听</p>}
                <div className="book-actions">
                  <Link href={`/books/${book.id}/listen`}>{book.lastListenedAt ? "继续收听" : "收听"}</Link>
                  <Link href={`/books/${book.id}/edit`}>校对</Link>
                  <button onClick={() => setEditing(book)}>编辑信息</button>
                  <button className="danger-link" onClick={() => setDeleting(book)}>删除</button>
                </div>
              </div>
            </article>
          ))}
        </section>
      ) : (
        <section className="empty-library" aria-labelledby="empty-title">
          <div className="empty-illustration"><span className="sound-wave wave-left" aria-hidden="true" /><span className="book-glyph"><BookIcon /></span><span className="sound-wave wave-right" aria-hidden="true" /></div>
          <p className="eyebrow">从一本喜欢的书开始</p><h2 id="empty-title">还没有书</h2>
          <p>上传 EPUB 或 PDF，我们会提取正文。扫描版 PDF 可以在 Windows Edge 中进行中英文 OCR。</p>
          <Link className="button button-primary" href="/import"><UploadIcon />上传第一本书</Link><small>支持无 DRM 的 EPUB、PDF，单个文件最大 200 MB</small>
        </section>
      )}

      {error && books.length > 0 && <p className="library-error" role="alert">{error}</p>}

      {editing && <div className="modal-backdrop" role="presentation" onMouseDown={(event) => { if (event.target === event.currentTarget && !working) setEditing(null); }}>
        <form className="book-dialog" role="dialog" aria-modal="true" aria-labelledby="edit-book-title" onSubmit={saveMetadata}>
          <header><p className="eyebrow">书籍设置</p><h2 id="edit-book-title">编辑信息与声音</h2></header>
          <label>书名<input name="title" defaultValue={editing.title} required /></label>
          <label>作者<input name="author" defaultValue={editing.author} required /></label>
          <label>封面图片<input name="cover" type="file" accept="image/jpeg,image/png,image/webp" /></label>
          <small className="dialog-hint">JPEG、PNG 或 WebP，最大 5 MB。选择新图片后会替换原封面。</small>
          {editing.coverUrl && <button className="danger-link dialog-cover-remove" type="button" disabled={working} onClick={() => void removeCover()}>移除当前封面</button>}
          <label>中文声音<select name="preferredZhVoice" defaultValue={editing.preferredZhVoice || DEFAULT_EDGE_VOICES["zh-CN"]}>{voiceOptions.zh.map(([value, label]) => <option key={value} value={value}>{label}</option>)}</select></label>
          <label>英文声音<select name="preferredEnVoice" defaultValue={editing.preferredEnVoice || DEFAULT_EDGE_VOICES["en-US"]}>{voiceOptions.en.map(([value, label]) => <option key={value} value={value}>{label}</option>)}</select></label>
          <label>默认播放速度<select name="preferredRate" defaultValue={editing.preferredRate ?? 1}>{[0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3].map((value) => <option key={value} value={value}>{value}×</option>)}</select></label>
          <div className="dialog-actions"><button className="button button-quiet" type="button" disabled={working} onClick={() => setEditing(null)}>取消</button><button className="button button-primary" disabled={working}>{working ? "保存中…" : "保存设置"}</button></div>
        </form>
      </div>}

      {deleting && <div className="modal-backdrop" role="presentation" onMouseDown={(event) => { if (event.target === event.currentTarget && !working) setDeleting(null); }}>
        <section className="book-dialog danger-dialog" role="alertdialog" aria-modal="true" aria-labelledby="delete-book-title">
          <p className="eyebrow">无法撤销</p><h2 id="delete-book-title">删除书籍？</h2>
          <p>将永久删除《{deleting.title}》的源文件、正文、播放进度和所有音频。</p>
          <div className="dialog-actions"><button className="button button-quiet" disabled={working} onClick={() => setDeleting(null)}>取消</button><button className="button button-danger" disabled={working} onClick={() => void deleteBook()}>{working ? "删除中…" : "删除书籍"}</button></div>
        </section>
      </div>}
    </main>
  );
}
