#!/usr/bin/env python3
"""
Quick EPUB packer (EPUB 2).
Usage:
  python make_epub.py --title "My Book" --author "Me" --lang zh --out /path/out.epub chapters/*.xhtml
The order of files in the CLI becomes the reading order.
"""
import argparse
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED, ZipInfo
import time
import os
import pathlib
from html import escape

def make_epub(title, author, language, out_epub, chapter_paths):
    out_epub = pathlib.Path(out_epub)
    book_id = (title.lower().replace(' ', '-') or "book-id") + "-id"

    # Build manifest/spine entries
    manifest_items = []
    spine_items = []
    navpoints = []

    # Normalize to relative names under OEBPS
    oebps_files = []
    for i, ch in enumerate(chapter_paths, start=1):
        ch = pathlib.Path(ch)
        if not ch.exists():
            raise FileNotFoundError(ch)
        rel_name = f"chapter{i}.xhtml"
        oebps_files.append((ch.read_text(encoding="utf-8"), rel_name, f"chapter{i}", ch.stem or f"Chapter {i}"))
        manifest_items.append(f'    <item id="chapter{i}" href="{rel_name}" media-type="application/xhtml+xml"/>')
        spine_items.append(f'    <itemref idref="chapter{i}"/>')
        navpoints.append("""    <navPoint id="navPoint-%d" playOrder="%d">
      <navLabel><text>%s</text></navLabel>
      <content src="%s"/>
    </navPoint>""" % (i, i, escape(ch.stem or f"Chapter {i}"), rel_name))

    container_xml = """<?xml version="1.0"?>
<container version="1.0"
           xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
   <rootfiles>
      <rootfile full-path="OEBPS/content.opf"
                media-type="application/oebps-package+xml"/>
   </rootfiles>
</container>
"""

    content_opf = f"""<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0"
         unique-identifier="BookId">

  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
    <dc:title>{escape(title)}</dc:title>
    <dc:creator>{escape(author)}</dc:creator>
    <dc:language>{escape(language)}</dc:language>
    <dc:identifier id="BookId">{escape(book_id)}</dc:identifier>
  </metadata>

  <manifest>
{os.linesep.join(manifest_items)}
    <item id="css" href="style.css" media-type="text/css"/>
    <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
  </manifest>

  <spine toc="ncx">
{os.linesep.join(spine_items)}
  </spine>

</package>
"""

    toc_ncx = f"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN"
  "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
  <head>
    <meta name="dtb:uid" content="{escape(book_id)}"/>
    <meta name="dtb:depth" content="1"/>
    <meta name="dtb:totalPageCount" content="0"/>
    <meta name="dtb:maxPageNumber" content="0"/>
  </head>
  <docTitle><text>{escape(title)}</text></docTitle>
  <navMap>
{os.linesep.join(navpoints)}
  </navMap>
</ncx>
"""

    style_css = "body { font-family: serif; line-height: 1.5; }\nh1 { text-align: center; }\n"

    # Write EPUB
    with ZipFile(out_epub, 'w') as zf:
        zinfo = ZipInfo(filename="mimetype", date_time=time.localtime()[:6])
        zinfo.compress_type = ZIP_STORED
        zf.writestr(zinfo, "application/epub+zip")
        zf.writestr("META-INF/container.xml", container_xml, compress_type=ZIP_DEFLATED)
        zf.writestr("OEBPS/content.opf", content_opf, compress_type=ZIP_DEFLATED)
        zf.writestr("OEBPS/toc.ncx", toc_ncx, compress_type=ZIP_DEFLATED)
        zf.writestr("OEBPS/style.css", style_css, compress_type=ZIP_DEFLATED)

        # Add chapters in order
        for html_text, rel_name, _id, _stem in oebps_files:
            # If chapter file already contains a full XHTML doc, keep as is.
            # If it's a fragment, wrap it (basic heuristic).
            if "<html" not in html_text.lower():
                html_text = """<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%s">
<head>
  <title>%s</title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
%s
</body>
</html>
""" % (escape(language), escape(title), html_text)
            zf.writestr(f"OEBPS/{rel_name}", html_text, compress_type=ZIP_DEFLATED)

    return str(out_epub)

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--title", required=True)
    ap.add_argument("--author", default="Unknown")
    ap.add_argument("--lang", default="zh")
    ap.add_argument("--out", required=True)
    ap.add_argument("chapters", nargs="+", help="Chapter XHTML/HTML files in reading order")
    args = ap.parse_args()
    path = make_epub(args.title, args.author, args.lang, args.out, args.chapters)
    print("Wrote:", path)

if __name__ == "__main__":
    main()
