import argparse
import asyncio
import os.path
import shutil
from pathlib import Path

import aiohttp
from aiohttp import web
from lxml import etree

from dev_tools.build.document.resources import DOCUMENT_BROWSER_BRANDING_ROOT


def _apply_branding(p: Path):
    text = p.read_text(encoding="utf-8")
    for src, trg in [
        (
            '<input type="hidden" id="init-product-branding-name" value="" />',
            '<input type="hidden" id="init-product-branding-name" value="Clarabot Nano Online Editor" />',
        ),
        (
            '<input type="hidden" id="init-product-branding-url" value="https://www.collaboraonline.com" />',
            '<input type="hidden" id="init-product-branding-url" value="https://www.clarabot.com" />',
        ),
    ]:
        if text.find(trg) >= 0:  # some could be set in config as well
            continue
        text2 = text.replace(src, trg, 1)
        if text == text2:
            raise Exception(f"No change to cool.html from {src} to {trg}")
        text = text2
    p.write_text(text, encoding="utf-8")
    for item in DOCUMENT_BROWSER_BRANDING_ROOT.iterdir():
        if item.is_dir():
            shutil.copytree(item, p.parent / item.name, dirs_exist_ok=True)
        else:
            shutil.copyfile(item, p.parent / item.name)


def _patch_frame_socket_proxy(p: Path):
    # Basically freeze a WSD build from:
    # https://github.com/Traktormaster/online/tree/nano-24.04.13-1
    global_js_path = p.parent / "global.js"
    text = global_js_path.read_text(encoding="utf-8")
    if (
        text.find("// Setup parent-frame proxy socket communication.") < 0
        and text.find("window.parentFrameSocketNumber=0;") < 0
    ):
        raise Exception("No parent-frame proxy socket patch?")


async def main():
    parser = argparse.ArgumentParser("Clarabot Nano - app builder utility")
    parser.add_argument("--wsd_port", type=int, default=9980)
    parser.add_argument("--source", default="/opt/collab/wsd/share/coolwsd/browser/dist")
    parser.add_argument("--target", default=os.path.expanduser("~/.clarabot-doc/browser"))
    args = parser.parse_args()

    src_path = Path(args.source)
    if not src_path.is_dir():
        raise Exception("Source path invalid\n" + str(src_path))

    wsd_url = f"http://127.0.0.1:{args.wsd_port}/"
    async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(force_close=True)) as session:
        async with session.get(f"{wsd_url}hosting/discovery") as resp:
            resp.raise_for_status()
            discovery_text = await resp.text()
        discovery = etree.fromstring(discovery_text)
        for action in discovery.xpath("/wopi-discovery/net-zone/app[@name='writer']/action"):
            url_src = action.get("urlsrc")
            if url_src:
                wsd_version_hash = url_src.rpartition("/browser/")[-1].rpartition("/cool.html")[0]
                if wsd_version_hash:
                    break
        else:
            raise Exception("Unknown discovery\n" + discovery_text)
        trg_path = Path(args.target, wsd_version_hash)
        if trg_path.exists():
            shutil.rmtree(trg_path)
        trg_path.mkdir(parents=True)

        print("Freezing", wsd_version_hash)
        print("  from", src_path)
        print("  to  ", trg_path)

        for dir_path, _, filenames in os.walk(src_path):
            for filename in filenames:
                file_path = Path(dir_path, filename)
                rel_path = file_path.relative_to(src_path)

                async with session.get(f"{wsd_url}browser/{wsd_version_hash}/{rel_path.as_posix()}") as resp:
                    try:
                        resp.raise_for_status()
                    except aiohttp.ClientResponseError as e:
                        if e.status == web.HTTPUnauthorized.status_code:
                            print("WARNING: Unauthorized", rel_path)
                        else:
                            raise e
                    else:
                        fin_path = trg_path / rel_path
                        fin_path.parent.mkdir(parents=True, exist_ok=True)
                        fin_path.write_bytes(await resp.read())

        # Patching...
        _patch_frame_socket_proxy(trg_path / "cool.html")
        _apply_branding(trg_path / "cool.html")


if __name__ == "__main__":
    asyncio.run(main())
