"""Install files.attachments hosts wrapping existing record composites.

Boilerplate trees are locally maintained. Wrappers mount record.table /
record.detail / state.empty for the admitted file_attachment relation.
They do not invent a second file store, Documents semantics, or upload UI.
"""
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 _captured_composition


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


def main():
    composition = _captured_composition(
        str(ROOT / "alembic/versions/141_file_attachments_pack.py"), "file-attachments"
    )
    fields = [{"key": f["key"], "label": f.get("name") or f["key"]} for f in composition["entities"][0]["schema"]["fields"]]
    schema_json = json.dumps({"fields": composition["entities"][0]["schema"]["fields"]}, indent=2) + "\n"
    for framework, lib in (("nuxt_app", "lib"), ("react_app", "src/lib"), ("html", "js")):
        write(
            ROOT / "boilerplates" / framework / lib / "entity-schemas" / "file_attachment.json",
            schema_json,
        )

    nuxt = ROOT / "boilerplates/nuxt_app/components/starter/blocks"
    write(nuxt / "AttachmentTable.vue", '''<script setup>
import AdminRecordTable from "./AdminRecordTable.vue";
defineProps({ emptyTitle: { type: String, default: "No attachments yet" } });
const emit = defineEmits(["select"]);
</script>
<template><AdminRecordTable entity-key="file_attachment" :empty-title="emptyTitle"
  :columns="[{key:'file_id',label:'File'},{key:'subject_entity_key',label:'Subject'},{key:'subject_record_id',label:'Record'}]"
  @select="emit('select', $event)" /></template>
''')
    write(nuxt / "AttachmentDetail.vue", '''<script setup>
import AdminRecordDetail from "./AdminRecordDetail.vue";
defineProps({ recordId: { type: String, required: true } });
const fields = ''' + json.dumps(fields) + ''';
</script>
<template><AdminRecordDetail entity-key="file_attachment" :record-id="recordId" title="Attachment" :fields="fields" /></template>
''')

    write(ROOT / "boilerplates/react_app/src/components/starter/files-blocks.jsx", '''import React from "react";
import { AdminRecordTable, AdminRecordDetail } from "./blocks";
import attachmentSchema from "../../lib/entity-schemas/file_attachment.json";
export function AttachmentTable(props) {
 return <AdminRecordTable {...props} entityKey="file_attachment" columns={[{key:"file_id",label:"File"},{key:"subject_entity_key",label:"Subject"},{key:"subject_record_id",label:"Record"}]} />;
}
export function AttachmentDetail(props) {
 return <AdminRecordDetail {...props} entityKey="file_attachment" fields={attachmentSchema.fields.map(f=>({key:f.key,label:f.name || f.key}))} />;
}
''')

    html = '''import { mountAdminRecordTable, mountAdminRecordDetail } from "./starter-blocks.js";
const attachmentSchema = ''' + json.dumps({"fields": composition["entities"][0]["schema"]["fields"]}) + ''';
export function mountAttachmentTable(root, props={}) {
 return mountAdminRecordTable(root,{...props,entityKey:"file_attachment",columns:[{key:"file_id",label:"File"},{key:"subject_entity_key",label:"Subject"},{key:"subject_record_id",label:"Record"}],emptyTitle:props.emptyTitle || "No attachments yet"});
}
export function mountAttachmentDetail(root, props={}) {
 return mountAdminRecordDetail(root,{...props,entityKey:"file_attachment",title:props.title || "Attachment",fields:attachmentSchema.fields.map(f=>({key:f.key,label:f.name || f.key}))});
}
'''
    write(ROOT / "boilerplates/html/js/files-blocks.js", html)

    impls = {
        "pipeline": {
            "nuxt_app": "components/starter/blocks/AttachmentTable.vue",
            "react_app": "src/components/starter/files-blocks.jsx#AttachmentTable",
            "html": "js/files-blocks.js#mountAttachmentTable",
        },
        "detail": {
            "nuxt_app": "components/starter/blocks/AttachmentDetail.vue",
            "react_app": "src/components/starter/files-blocks.jsx#AttachmentDetail",
            "html": "js/files-blocks.js#mountAttachmentDetail",
        },
    }
    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"] != "files.attachments":
                continue
            if host["slot"] == "empty":
                empty = existing_by_key.get(("crm.customer", "empty")) or existing_by_key.get(("task.management", "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"] == "files.attachments"]
        if len(mapped) != 3:
            raise SystemExit(f"unmapped files.attachments slots for {framework}: {mapped}")
        write(path, json.dumps(hosts, indent=2) + "\n")
    print("files.attachments hosts materialized")


if __name__ == "__main__":
    main()
