from __future__ import annotations

import argparse
import asyncio
import json
from pathlib import Path

from .data_store import MockDataStore
from .export_introspection import write_profiles
from .profiles import list_profiles, load_profile
from .server import FocasMockServer


def _default_root() -> Path:
    return Path(__file__).resolve().parents[2]


def build_parser() -> argparse.ArgumentParser:
    root = _default_root()
    parser = argparse.ArgumentParser(prog="focas-mock")
    sub = parser.add_subparsers(dest="command", required=True)

    serve = sub.add_parser("serve", help="Start the mock server.")
    serve.add_argument("--host", default="127.0.0.1")
    serve.add_argument("--port", type=int, default=8193)
    serve.add_argument("--profile", default="fwlib30i64")
    serve.add_argument("--data", help="Optional JSON patch file.")

    sub.add_parser("list-profiles", help="List built-in profiles.")

    dump_profile = sub.add_parser("dump-profile", help="Print one built-in profile as JSON.")
    dump_profile.add_argument("profile")

    extract = sub.add_parser("extract-profiles", help="Regenerate JSON profiles from vendored DLLs.")
    extract.add_argument("--dll-dir", default=str(root / "vendor" / "fanuc-cnc-api" / "64bit"))
    extract.add_argument("--fwlib", default=str(root / "upstream" / "fwlib.cs"))
    extract.add_argument("--out-dir", default=str(root / "src" / "focas_mock" / "builtin_profiles"))
    return parser


async def _run_server(args: argparse.Namespace) -> None:
    profile = load_profile(args.profile)
    store = MockDataStore(profile)
    if args.data:
        store.load_patch_file(args.data)
    server = FocasMockServer(args.host, args.port, profile, store)
    await server.start()
    print(f"focas-mock listening on {server.host}:{server.port} with profile {profile['profile_name']}")
    try:
        await server.serve_forever()
    finally:
        await server.close()


def main(argv: list[str] | None = None) -> None:
    parser = build_parser()
    args = parser.parse_args(argv)

    if args.command == "list-profiles":
        for profile in list_profiles():
            print(profile)
        return

    if args.command == "dump-profile":
        print(json.dumps(load_profile(args.profile), indent=2))
        return

    if args.command == "extract-profiles":
        written = write_profiles(args.dll_dir, args.fwlib, args.out_dir)
        for path in written:
            print(path)
        return

    if args.command == "serve":
        asyncio.run(_run_server(args))
        return


if __name__ == "__main__":
    main()
