"""Install catalog.product hosts wrapping existing record composites.

Boilerplate trees are locally maintained. Wrappers mount record.table /
record.create / record.edit; they do not invent a catalog engine or bind
checkout products.
"""
from __future__ import annotations

import json
from pathlib import Path
import sys

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from src.domain.app_blocks.hosts import merge_host_map
from tests.test_phase11_pack_migration_materialization import _load_migration


def write(path, text):
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(text, encoding="utf-8")


def main():
    catalog = _load_migration(
        str(ROOT / "alembic/versions/145_product_catalog_pack.py")
    ).catalog_composition()["entities"][0]["schema"]
    fields = [{"key": f["key"], "label": f["name"]} for f in catalog["fields"]]
    schema_json = json.dumps({"fields": catalog["fields"]}, indent=2) + "\n"
    for framework, lib in (("nuxt_app", "lib"), ("react_app", "src/lib"), ("html", "js")):
        write(
            ROOT / "boilerplates" / framework / lib / "entity-schemas" / "catalog_item.json",
            schema_json,
        )

    nuxt = ROOT / "boilerplates/nuxt_app/components/starter/blocks"
    write(nuxt / "CatalogTable.vue", '''<script setup>
import AdminRecordTable from "./AdminRecordTable.vue";
defineProps({ emptyTitle: { type: String, default: "No catalog items yet" } });
const emit = defineEmits(["select"]);
</script>
<template><AdminRecordTable entity-key="catalog_item" :empty-title="emptyTitle"
  :columns="[{key:'name',label:'Name'},{key:'sku',label:'SKU'},{key:'status',label:'Status'}]"
  @select="emit('select', $event)" /></template>
''')
    write(nuxt / "CatalogDetail.vue", '''<script setup>
import AdminRecordDetail from "./AdminRecordDetail.vue";
defineProps({ recordId: { type: String, required: true } });
const fields = ''' + json.dumps(fields) + ''';
</script>
<template><AdminRecordDetail entity-key="catalog_item" :record-id="recordId" title="Catalog item" :fields="fields" /></template>
''')
    for action in ("Create", "Edit"):
        edit = action == "Edit"
        write(nuxt / f"Catalog{action}.vue", f'''<script setup>
import schema from "~/lib/entity-schemas/catalog_item.json";
import Record{action} from "../Record{action}.vue";
defineProps({{ recordId: {{ type: String, default: "" }} }});
const emit = defineEmits(["{'updated' if edit else 'created'}"]);
</script>
<template><Record{action} entity-key="catalog_item" :schema="schema" {' :record-id="recordId"' if edit else ''}
 heading="{action} catalog item" @{'updated' if edit else 'created'}="emit('{'updated' if edit else 'created'}', $event)" /></template>
''')

    write(ROOT / "boilerplates/react_app/src/components/starter/catalog-blocks.jsx", '''import React from "react";
import { AdminRecordTable, AdminRecordDetail } from "./blocks";
import { RecordCreate } from "./RecordCreate";
import { RecordEdit } from "./RecordEdit";
import catalogSchema from "../../lib/entity-schemas/catalog_item.json";
export function CatalogTable(props) {
 return <AdminRecordTable {...props} entityKey="catalog_item" columns={[{key:"name",label:"Name"},{key:"sku",label:"SKU"},{key:"status",label:"Status"}]} />;
}
export function CatalogDetail(props) {
 return <AdminRecordDetail {...props} entityKey="catalog_item" fields={catalogSchema.fields.map(f=>({key:f.key,label:f.name}))} />;
}
export function CatalogCreate(props) {
 return <RecordCreate {...props} entityKey="catalog_item" schema={catalogSchema} heading="Create catalog item" />;
}
export function CatalogEdit(props) {
 return <RecordEdit {...props} entityKey="catalog_item" schema={catalogSchema} heading="Edit catalog item" />;
}
''')

    html = '''import { mountAdminRecordTable, mountAdminRecordDetail, mountRecordCreate, mountRecordEdit } from "./starter-blocks.js";
'''
    html += "const catalogSchema = " + json.dumps({"fields": catalog["fields"]}) + ";\n"
    html += '''export function mountCatalogTable(root, props={}) {
 return mountAdminRecordTable(root,{...props,entityKey:"catalog_item",columns:[{key:"name",label:"Name"},{key:"sku",label:"SKU"},{key:"status",label:"Status"}]});
}
export function mountCatalogDetail(root, props={}) {
 return mountAdminRecordDetail(root,{...props,entityKey:"catalog_item",fields:catalogSchema.fields.map(f=>({key:f.key,label:f.name}))});
}
export function mountCatalogCreate(root, props={}) {
 return mountRecordCreate(root,{...props,entityKey:"catalog_item",schema:catalogSchema,heading:"Create catalog item"});
}
export function mountCatalogEdit(root, props={}) {
 return mountRecordEdit(root,{...props,entityKey:"catalog_item",schema:catalogSchema,heading:"Edit catalog item"});
}
'''
    write(ROOT / "boilerplates/html/js/catalog-blocks.js", html)

    impls = {
        "list": {"nuxt_app": "components/starter/blocks/CatalogTable.vue",
                 "react_app": "src/components/starter/catalog-blocks.jsx#CatalogTable",
                 "html": "js/catalog-blocks.js#mountCatalogTable"},
        "detail": {"nuxt_app": "components/starter/blocks/CatalogDetail.vue",
                   "react_app": "src/components/starter/catalog-blocks.jsx#CatalogDetail",
                   "html": "js/catalog-blocks.js#mountCatalogDetail"},
        "create": {"nuxt_app": "components/starter/blocks/CatalogCreate.vue",
                   "react_app": "src/components/starter/catalog-blocks.jsx#CatalogCreate",
                   "html": "js/catalog-blocks.js#mountCatalogCreate"},
        "edit": {"nuxt_app": "components/starter/blocks/CatalogEdit.vue",
                 "react_app": "src/components/starter/catalog-blocks.jsx#CatalogEdit",
                 "html": "js/catalog-blocks.js#mountCatalogEdit"},
    }
    for framework in ("nuxt_app", "react_app", "html"):
        path = ROOT / "boilerplates" / framework / "p2hs/app-block-hosts.json"
        existing = json.loads(path.read_text(encoding="utf-8"))
        hosts = merge_host_map(existing)
        existing_by_key = {(h["block"], h["slot"]): h for h in existing["hosts"]}
        for host in hosts["hosts"]:
            if host["block"] != "catalog.product":
                continue
            if host["slot"] == "empty":
                empty = existing_by_key.get(("crm.customer", "empty")) or existing_by_key.get(("crm.lead", "empty"))
                host["implementation"] = empty["implementation"]
                continue
            host["implementation"] = impls[host["slot"]][framework]
        hosts["hosts"] = [host for host in hosts["hosts"] if host.get("implementation")]
        mapped = [h for h in hosts["hosts"] if h["block"] == "catalog.product"]
        if len(mapped) != 5:
            raise SystemExit(f"unmapped catalog slots for {framework}: {mapped}")
        write(path, json.dumps(hosts, indent=2) + "\n")
    print("catalog.product hosts materialized")


if __name__ == "__main__":
    main()
