import { useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { Button, Divider, Flex, Popconfirm, Select, Skeleton, Tag, Tooltip, Typography, message } from 'antd'
import {
  ArrowLeftOutlined,
  AudioOutlined,
  BankOutlined,
  CalendarOutlined,
  DeleteOutlined,
  DownOutlined,
  EditOutlined,
  FileTextOutlined,
  FolderOutlined,
  LinkOutlined,
  ReadOutlined,
  SearchOutlined,
  StarFilled,
  StarOutlined,
  TabletOutlined,
  TagsOutlined,
} from '@ant-design/icons'
import type { Book, BookFile, Edition, FileFormat, ReadingFormat, WantedBook } from '../../types'

const EBOOK_FORMATS:     FileFormat[] = ['epub', 'mobi', 'pdf']
const AUDIOBOOK_FORMATS: FileFormat[] = ['m4b', 'mp3', 'aac', 'flac']
import { fetchBook } from '../../api/books'
import { assignFile, deleteFile, fetchBookFiles, organizeFile, writeFileMetadata, writeBookMetadata } from '../../api/files'
import { addWanted, fetchWanted, removeWanted } from '../../api/wanted'
import s from './BookDetail.module.css'

export default function BookDetail() {
  const { id } = useParams<{ id: string }>()
  const navigate = useNavigate()
  const [book, setBook]               = useState<Book | null>(null)
  const [loading, setLoading]         = useState(true)
  const [files, setFiles]             = useState<BookFile[]>([])
  const [editionsOpen, setEditionsOpen] = useState(false)
  const [writingAll, setWritingAll]   = useState(false)
  const [wanted, setWanted]           = useState<WantedBook | null>(null)
  const [toggling, setToggling]       = useState(false)

  useEffect(() => {
    if (!id) return
    setLoading(true)
    fetchBook(Number(id))
      .then(b => {
        setBook(b)
        return Promise.all([
          fetchBookFiles(b.id),
          fetchWanted().then(ws => ws.find(w => w.bookId === b.id) ?? null),
        ])
      })
      .then(([fs, w]) => { setFiles(fs); setWanted(w) })
      .catch(() => setBook(null))
      .finally(() => setLoading(false))
  }, [id])

  async function handleToggleMonitor() {
    if (!book) return
    setToggling(true)
    try {
      if (wanted) {
        await removeWanted(wanted.id)
        setWanted(null)
        message.success('Removed from monitoring.')
      } else {
        const w = await addWanted(book.id)
        setWanted(w)
        message.success('Book is now monitored.')
      }
    } catch {
      message.error('Failed to update monitoring.')
    } finally {
      setToggling(false)
    }
  }

  function handleUnlink(fileId: number) {
    assignFile(fileId, null, null).then(updated =>
      setFiles(fs => fs.map(f => f.id === fileId ? updated : f))
    )
  }

  function handleDeleteFile(fileId: number) {
    deleteFile(fileId).then(() => setFiles(fs => fs.filter(f => f.id !== fileId)))
  }

  function handleAssignEdition(fileId: number, bookId: number | null, editionId: number | null) {
    assignFile(fileId, bookId, editionId).then(updated =>
      setFiles(fs => fs.map(f => f.id === fileId ? updated : f))
    )
  }

  function handleOrganize(fileId: number) {
    organizeFile(fileId).then(result => {
      if (result.moved)
        setFiles(fs => fs.map(f => f.id === fileId
          ? { ...f, path: result.newRelativePath, filename: result.newFilename }
          : f
        ))
    })
  }

  function handleWriteMetadata(fileId: number) {
    return writeFileMetadata(fileId).then(r => {
      if (r.success) message.success(r.message)
      else           message.error(r.message)
    })
  }

  function handleWriteAllMetadata() {
    if (!book) return
    setWritingAll(true)
    writeBookMetadata(book.id)
      .then(r => {
        const failed = r.results.filter(x => !x.success)
        if (failed.length === 0)
          message.success(`Metadata written to ${r.results.length} file(s).`)
        else
          message.warning(`${r.results.length - failed.length} succeeded, ${failed.length} failed.`)
      })
      .finally(() => setWritingAll(false))
  }

  return (
    <div className={s.page}>
      <div className={s.content}>

        {/* Back + actions */}
        <Flex align="center" gap={12} className={s.header}>
          <Button
            icon={<ArrowLeftOutlined />}
            onClick={() => navigate('/library')}
          >
            Library
          </Button>
          <div style={{ flex: 1 }} />
          {book && (
            <>
              <Tooltip title={wanted ? 'Monitored — click to unmonitor' : 'Monitor for downloads'}>
                <Button
                  icon={wanted ? <StarFilled style={{ color: '#6750A4' }} /> : <StarOutlined />}
                  loading={toggling}
                  onClick={handleToggleMonitor}
                />
              </Tooltip>
              <Button
                icon={<SearchOutlined />}
                onClick={() => navigate(`/import?tab=search&q=${encodeURIComponent(book.title)}`)}
              >
                Find Downloads
              </Button>
              <Button
                type="primary"
                icon={<EditOutlined />}
                onClick={() => navigate(`/metadata?bookId=${book.id}`)}
              >
                Edit Metadata
              </Button>
            </>
          )}
        </Flex>

        {loading && <BookSkeleton />}

        {!loading && !book && (
          <Flex justify="center" align="center" style={{ padding: '80px 0' }}>
            <Typography.Text type="secondary">Book not found.</Typography.Text>
          </Flex>
        )}

        {!loading && book && (
          <>
            {/* Hero */}
            <Flex gap={36} align="flex-start" className={s.hero}>
              <div className={s.cover} style={{ background: book.color }}>
                {book.coverUrl
                  ? <img src={book.coverUrl} alt={book.title} className={s.coverImg} />
                  : <span className={s.coverInitials}>
                      {book.title.split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase()}
                    </span>
                }
              </div>

              <div className={s.info}>
                <Typography.Title level={2} style={{ margin: 0, lineHeight: 1.2 }}>
                  {book.title}
                </Typography.Title>

                <Typography.Text style={{ fontSize: 16, color: 'rgba(0,0,0,.65)' }}>
                  {book.authors.map(a => a.name).join(', ')}
                </Typography.Text>

                {book.series && (
                  <Typography.Text style={{ fontSize: 14, color: '#6750A4' }}>
                    {book.series.name} · Book {book.series.position}
                    {book.series.arc ? ` · ${book.series.arc}` : ''}
                  </Typography.Text>
                )}

                <Divider style={{ margin: '12px 0' }} />

                <div className={s.stats}>
                  {book.year      && <StatRow icon={<CalendarOutlined />} label="Year"      value={String(book.year)} />}
                  {book.pages     && <StatRow icon={<FileTextOutlined />} label="Pages"     value={String(book.pages)} />}
                  {book.publisher && <StatRow icon={<BankOutlined />}     label="Publisher" value={book.publisher} />}
                </div>

                {book.formats.length > 0 && (
                  <Flex gap={6} wrap="wrap">
                    {book.formats.map(f => (
                      <Tag key={f}>{f.toUpperCase()}</Tag>
                    ))}
                  </Flex>
                )}

                {book.genres.length > 0 && (
                  <Flex gap={6} wrap="wrap">
                    {book.genres.map(g => (
                      <Tag key={g} color="purple">{g}</Tag>
                    ))}
                  </Flex>
                )}

                {book.localFileFormats.length > 0 && (
                  <Flex gap={8} align="center">
                    {book.localFileFormats.some(f => EBOOK_FORMATS.includes(f)) && (
                      <Flex gap={6} align="center" style={{
                        padding: '3px 10px', borderRadius: 20,
                        background: '#f0f5ff', border: '1px solid #adc6ff',
                        fontSize: 13, color: '#2f54eb',
                      }}>
                        <TabletOutlined />
                        <span>Ebook</span>
                      </Flex>
                    )}
                    {book.localFileFormats.some(f => AUDIOBOOK_FORMATS.includes(f)) && (
                      <Flex gap={6} align="center" style={{
                        padding: '3px 10px', borderRadius: 20,
                        background: '#f9f0ff', border: '1px solid #d3adf7',
                        fontSize: 13, color: '#722ed1',
                      }}>
                        <AudioOutlined />
                        <span>Audiobook</span>
                      </Flex>
                    )}
                  </Flex>
                )}
              </div>
            </Flex>

            {/* Description */}
            {book.description && (
              <section className={s.section}>
                <Typography.Title level={5} style={{ marginBottom: 10 }}>About</Typography.Title>
                <Typography.Paragraph style={{ fontSize: 14, lineHeight: 1.7, color: 'rgba(0,0,0,.75)', marginBottom: 0 }}>
                  {book.description}
                </Typography.Paragraph>
              </section>
            )}

            {/* Editions */}
            {(() => {
              const filtered = book.editions.filter(ed =>
                !ed.language || ed.language === 'English' || ed.language === 'Latvian'
              )
              return filtered.length > 0 ? (
                <section className={s.section}>
                  <button
                    onClick={() => setEditionsOpen(o => !o)}
                    style={{
                      display: 'flex', alignItems: 'center', gap: 6,
                      background: 'none', border: 'none', cursor: 'pointer', padding: 0,
                      marginBottom: editionsOpen ? 10 : 0,
                    }}
                  >
                    <Typography.Title level={5} style={{ margin: 0 }}>
                      Editions from Hardcover ({filtered.length})
                    </Typography.Title>
                    <DownOutlined
                      style={{
                        fontSize: 11, color: 'rgba(0,0,0,.45)',
                        transition: 'transform .2s',
                        transform: editionsOpen ? 'rotate(180deg)' : 'rotate(0deg)',
                      }}
                    />
                  </button>
                  {editionsOpen && (
                    <div className={s.editionList}>
                      {filtered.map(ed => (
                        <EditionRow key={ed.id} edition={ed} />
                      ))}
                    </div>
                  )}
                </section>
              ) : null
            })()}

            {/* Files */}
            <section className={s.section}>
              <Flex align="center" gap={8} style={{ marginBottom: 10 }}>
                <Typography.Title level={5} style={{ margin: 0 }}>
                  Files {files.length > 0 && `(${files.length})`}
                </Typography.Title>
                {files.length > 0 && (
                  <Tooltip title="Write metadata to all files">
                    <Button
                      size="small"
                      icon={<TagsOutlined />}
                      loading={writingAll}
                      onClick={handleWriteAllMetadata}
                    >
                      Write Metadata
                    </Button>
                  </Tooltip>
                )}
              </Flex>
              {files.length === 0 ? (
                <Typography.Text type="secondary" style={{ fontSize: 13 }}>
                  No files linked to this book.
                </Typography.Text>
              ) : (
                <div className={s.editionList}>
                  {files.map(f => (
                    <FileRow
                      key={f.id}
                      file={f}
                      editions={book.editions.filter(ed =>
                        !ed.language || ed.language === 'English' || ed.language === 'Latvian'
                      )}
                      onUnlink={handleUnlink}
                      onDelete={handleDeleteFile}
                      onAssignEdition={handleAssignEdition}
                      onOrganize={handleOrganize}
                      onWriteMetadata={handleWriteMetadata}
                    />
                  ))}
                </div>
              )}
            </section>
          </>
        )}
      </div>
    </div>
  )
}

function StatRow({ icon, label, value }: { icon: React.ReactNode; label: string; value: string }) {
  return (
    <Flex align="flex-start" gap={10}>
      <span style={{ color: 'rgba(0,0,0,.4)', fontSize: 16, marginTop: 2, display: 'flex' }}>{icon}</span>
      <div>
        <div style={{ fontSize: 11, color: 'rgba(0,0,0,.4)', textTransform: 'uppercase', letterSpacing: '.06em' }}>
          {label}
        </div>
        <div style={{ fontSize: 14, color: 'rgba(0,0,0,.85)' }}>{value}</div>
      </div>
    </Flex>
  )
}

const FORMAT_ICON: Record<ReadingFormat, React.ReactNode> = {
  Physical: <ReadOutlined />,
  Audio:    <AudioOutlined />,
  Both:     <ReadOutlined />,
  Ebook:    <TabletOutlined />,
}

function formatAudio(seconds: number): string {
  const h = Math.floor(seconds / 3600)
  const m = Math.floor((seconds % 3600) / 60)
  return h > 0 ? `${h}h ${m}m` : `${m}m`
}

function EditionRow({ edition }: { edition: Edition }) {
  const icon  = edition.readingFormat ? FORMAT_ICON[edition.readingFormat] : <ReadOutlined />
  const label = edition.editionFormat ?? edition.readingFormat ?? null

  const meta: string[] = []
  if (edition.publisher)   meta.push(edition.publisher)
  if (edition.releaseYear) meta.push(String(edition.releaseYear))
  if (edition.pages)       meta.push(`${edition.pages} pp`)
  if (edition.audioSeconds) meta.push(formatAudio(edition.audioSeconds))
  if (edition.language && edition.language !== 'English') meta.push(edition.language)  // shows "Latvian" etc.

  return (
    <Flex gap={12} align="flex-start" className={s.editionRow}>
      <span style={{ color: 'rgba(0,0,0,.45)', fontSize: 18, display: 'flex', marginTop: 2 }}>{icon}</span>
      <div>
        {label && (
          <Typography.Text style={{ fontSize: 13, fontWeight: 500 }}>{label}</Typography.Text>
        )}
        {edition.isbn && (
          <Typography.Text
            type="secondary"
            style={{ fontSize: 12, fontFamily: 'monospace', display: 'block' }}
          >
            ISBN: {edition.isbn}
          </Typography.Text>
        )}
        {!edition.isbn && edition.asin && (
          <Typography.Text
            type="secondary"
            style={{ fontSize: 12, fontFamily: 'monospace', display: 'block' }}
          >
            ASIN: {edition.asin}
          </Typography.Text>
        )}
        {meta.length > 0 && (
          <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block' }}>
            {meta.join(' · ')}
          </Typography.Text>
        )}
      </div>
    </Flex>
  )
}

function formatBytes(bytes: number): string {
  if (bytes >= 1_073_741_824) return `${(bytes / 1_073_741_824).toFixed(1)} GB`
  if (bytes >= 1_048_576)     return `${(bytes / 1_048_576).toFixed(1)} MB`
  if (bytes >= 1_024)         return `${(bytes / 1_024).toFixed(0)} KB`
  return `${bytes} B`
}

function editionLabel(ed: Edition): string {
  const parts: string[] = []
  if (ed.editionFormat) parts.push(ed.editionFormat)
  else if (ed.readingFormat) parts.push(ed.readingFormat)
  if (ed.releaseYear) parts.push(String(ed.releaseYear))
  if (ed.isbn) parts.push(`ISBN ${ed.isbn}`)
  else if (ed.asin) parts.push(`ASIN ${ed.asin}`)
  return parts.join(' · ') || `Edition #${ed.id}`
}

function FileRow({
  file,
  editions,
  onUnlink,
  onDelete,
  onAssignEdition,
  onOrganize,
  onWriteMetadata,
}: {
  file: BookFile
  editions: Edition[]
  onUnlink: (id: number) => void
  onDelete: (id: number) => void
  onAssignEdition: (fileId: number, bookId: number | null, editionId: number | null) => void
  onOrganize: (id: number) => void
  onWriteMetadata: (id: number) => void
}) {
  const [writing, setWriting] = useState(false)

  function handleWrite() {
    setWriting(true)
    onWriteMetadata(file.id).finally(() => setWriting(false))
  }
  return (
    <Flex gap={12} align="center" className={s.editionRow} style={{ flexWrap: 'wrap' }}>
      <Tag style={{ fontFamily: 'monospace', textTransform: 'uppercase', margin: 0, flexShrink: 0 }}>
        {file.format}
      </Tag>
      <div style={{ flex: 1, minWidth: 0 }}>
        <Typography.Text
          ellipsis
          style={{ display: 'block', fontSize: 13, fontWeight: 500 }}
        >
          {file.filename}
        </Typography.Text>
        <Typography.Text type="secondary" style={{ fontSize: 12 }}>
          {formatBytes(file.sizeBytes)}
        </Typography.Text>
      </div>
      {editions.length > 0 && (
        <Select
          size="small"
          allowClear
          placeholder="Edition"
          value={file.editionId ?? undefined}
          onChange={(val: number | undefined) =>
            onAssignEdition(file.id, file.bookId ?? null, val ?? null)
          }
          style={{ width: 200, fontSize: 12 }}
          options={editions.map(ed => ({ value: ed.id, label: editionLabel(ed) }))}
        />
      )}
      <Flex gap={4}>
        <Tooltip title="Write metadata to file">
          <Button
            size="small"
            icon={<TagsOutlined />}
            loading={writing}
            onClick={handleWrite}
          />
        </Tooltip>
        <Tooltip title="Move to canonical library path">
          <Button
            size="small"
            icon={<FolderOutlined />}
            onClick={() => onOrganize(file.id)}
          />
        </Tooltip>
        <Tooltip title="Unlink from book">
          <Button
            size="small"
            icon={<LinkOutlined />}
            onClick={() => onUnlink(file.id)}
          />
        </Tooltip>
        <Popconfirm
          title="Remove this file record?"
          description="The file on disk is not deleted."
          onConfirm={() => onDelete(file.id)}
          okText="Remove"
          okType="danger"
        >
          <Button size="small" icon={<DeleteOutlined />} danger title="Remove record" />
        </Popconfirm>
      </Flex>
    </Flex>
  )
}

function BookSkeleton() {
  return (
    <Flex gap={36} align="flex-start" style={{ padding: '24px 0' }}>
      <Skeleton.Image active style={{ width: 180, height: 270, borderRadius: 8 }} />
      <div style={{ flex: 1 }}>
        <Skeleton active paragraph={{ rows: 5 }} />
      </div>
    </Flex>
  )
}
