"""Install status-only record.edit hosts for the 12D workflow product surfaces.

Reproduces the existing crm.pipeline pattern:

    inspect host (record.detail)
    + record.edit visible_fields=["status"] → adapter.records.patchRecord
    → Cloud workflow.transition

Boilerplate trees are locally maintained. This script is the versioned
recipe. No new adapter, route, primitive, or workflow graph.
"""
from __future__ import annotations

import json
import re
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_crm_authorization_11e2 import lead_composition
from tests.test_phase11_pack_migration_materialization import _captured_composition

BLOCKS = (
    {
        "block": "task.management",
        "entity_key": "platform_task",
        "schema_file": "platform_task",
        "detail": "TaskDetail",
        "status": "TaskStatusEdit",
        "title": "Task",
        "heading": "Change status",
        "fields": [
            {"key": "title", "label": "Title"},
            {"key": "description", "label": "Description"},
            {"key": "status", "label": "Status"},
            {"key": "due_date", "label": "Due Date"},
            {"key": "subject_entity_key", "label": "Subject Entity"},
            {"key": "subject_record_id", "label": "Subject Record"},
        ],
    },
    {
        "block": "case.management",
        "entity_key": "case_record",
        "schema_file": "case_record",
        "detail": "CaseDetail",
        "status": "CaseStatusEdit",
        "title": "Case",
        "heading": "Change status",
        "fields": [
            {"key": "title", "label": "Title"},
            {"key": "reference", "label": "Reference"},
            {"key": "applicant", "label": "Applicant"},
            {"key": "email", "label": "Email"},
            {"key": "status", "label": "Status"},
            {"key": "notes", "label": "Notes"},
        ],
    },
    {
        "block": "workflow.assignment",
        "entity_key": "assignment",
        "schema_file": "assignment",
        "detail": "AssignmentDetail",
        "status": "AssignmentStatusEdit",
        "title": "Assignment",
        "heading": "Change status",
        "fields": [
            {"key": "subject_entity_key", "label": "Subject Entity"},
            {"key": "subject_record_id", "label": "Subject Record"},
            {"key": "assigned_to", "label": "Assigned To"},
            {"key": "assigned_by", "label": "Assigned By"},
            {"key": "status", "label": "Status"},
        ],
    },
)


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


def _schema_fields(composition: dict) -> list[dict]:
    return list(composition["entities"][0]["schema"]["fields"])


def _nuxt_detail(spec: dict) -> str:
    fields = json.dumps(spec["fields"])
    return f'''<script setup>
import schema from "~/lib/entity-schemas/{spec["schema_file"]}.json";
import AdminRecordDetail from "~/components/starter/blocks/AdminRecordDetail.vue";
import RecordEdit from "../RecordEdit.vue";

defineProps({{
  recordId: {{ type: String, default: "" }},
  title: {{ type: String, default: "{spec["title"]}" }},
}});
</script>

<template>
  <section>
    <AdminRecordDetail
      entity-key="{spec["entity_key"]}"
      :record-id="recordId"
      :title="title"
      :fields='{fields}'
    />
    <RecordEdit
      entity-key="{spec["entity_key"]}"
      :record-id="recordId"
      :schema="schema"
      :visible-fields="['status']"
      heading="{spec["heading"]}"
      submit-label="{spec["heading"]}"
    />
  </section>
</template>
'''


def _nuxt_status(
    spec: dict,
    *,
    entity_key: str,
    schema_file: str,
    heading: str,
    submit_label: str | None = None,
) -> str:
    submit = submit_label or heading
    return f'''<script setup>
import schema from "~/lib/entity-schemas/{schema_file}.json";
import RecordEdit from "../RecordEdit.vue";
defineProps({{ recordId: {{ type: String, required: true }} }});
</script>
<template>
  <RecordEdit
    entity-key="{entity_key}"
    :record-id="recordId"
    :schema="schema"
    :visible-fields="['status']"
    heading="{heading}"
    submit-label="{submit}"
  />
</template>
'''


def _replace_function(source: str, name: str, body: str) -> str:
    pattern = re.compile(
        rf"export function {name}\([^)]*\) \{{.*?\n\}}\n",
        re.DOTALL,
    )
    updated, count = pattern.subn(body.rstrip() + "\n", source, count=1)
    if count != 1:
        raise SystemExit(f"expected exactly one export function {name}, found {count}")
    return updated


def _ensure_react_imports(source: str, files: list[str]) -> str:
    for name in files:
        needle = f'import {name}Schema from "../../lib/entity-schemas/{name}.json";'
        if needle not in source:
            source = source.replace(
                'import documentSchema from "../../lib/entity-schemas/document.json";',
                'import documentSchema from "../../lib/entity-schemas/document.json";\n'
                + needle,
            )
    return source


def _html_combined(spec: dict) -> str:
    fields = json.dumps(spec["fields"], indent=6)
    return f'''export function mount{spec["detail"]}(root, props = {{}}) {{
  const detail = document.createElement("section");
  const edit = document.createElement("section");
  root.replaceChildren(detail, edit);
  mountAdminRecordDetail(detail, {{
    entityKey: "{spec["entity_key"]}",
    recordId: props.recordId || "",
    title: props.title || "{spec["title"]}",
    fields: {fields},
  }});
  return mountRecordEdit(edit, {{
    ...props,
    entityKey: "{spec["entity_key"]}",
    schema: {spec["schema_file"]}Schema,
    visibleFields: ["status"],
    heading: "{spec["heading"]}",
    submitLabel: "{spec["heading"]}",
  }});
}}
'''


def main() -> None:
    schemas = {
        "platform_task": _schema_fields(
            _captured_composition("alembic/versions/137_task_management_pack.py", "task-management")
        ),
        "case_record": _schema_fields(
            _captured_composition("alembic/versions/133_case_lifecycle_pack.py", "case-lifecycle")
        ),
        "assignment": _schema_fields(
            _captured_composition("alembic/versions/136_assignment_tracking_pack.py", "assignment-tracking")
        ),
        "lead": _schema_fields(lead_composition()),
    }
    for framework, lib in (("nuxt_app", "lib"), ("react_app", "src/lib"), ("html", "js")):
        for key, fields in schemas.items():
            write(
                ROOT / "boilerplates" / framework / lib / "entity-schemas" / f"{key}.json",
                json.dumps({"fields": fields}, indent=2) + "\n",
            )

    nuxt = ROOT / "boilerplates/nuxt_app/components/starter/blocks"
    for spec in BLOCKS:
        write(nuxt / f"{spec['detail']}.vue", _nuxt_detail(spec))
        write(
            nuxt / f"{spec['status']}.vue",
            _nuxt_status(
                spec,
                entity_key=spec["entity_key"],
                schema_file=spec["schema_file"],
                heading=spec["heading"],
            ),
        )
    write(
        nuxt / "PipelineStatusEdit.vue",
        _nuxt_status(
            {},
            entity_key="lead",
            schema_file="lead",
            heading="Change pipeline stage",
            submit_label="Change stage",
        ),
    )

    react_blocks = ROOT / "boilerplates/react_app/src/components/starter/blocks.jsx"
    react_source = _ensure_react_imports(
        react_blocks.read_text(encoding="utf-8"),
        ["platform_task", "case_record", "assignment"],
    )
    react_fns = {
        "CaseDetail": '''export function CaseDetail({ recordId = "", title = "Case" }) {
  return (
    <section>
      <AdminRecordDetail
        entityKey="case_record"
        recordId={recordId}
        title={title}
        fields={[
          { key: "title", label: "Title" },
          { key: "reference", label: "Reference" },
          { key: "applicant", label: "Applicant" },
          { key: "email", label: "Email" },
          { key: "status", label: "Status" },
          { key: "notes", label: "Notes" },
        ]}
      />
      <RecordEdit
        entityKey="case_record"
        recordId={recordId}
        schema={case_recordSchema}
        visibleFields={["status"]}
        heading="Change status"
        submitLabel="Change status"
      />
    </section>
  );
}
''',
        "AssignmentDetail": '''export function AssignmentDetail({ recordId = "", title = "Assignment" }) {
  return (
    <section>
      <AdminRecordDetail
        entityKey="assignment"
        recordId={recordId}
        title={title}
        fields={[
          { key: "subject_entity_key", label: "Subject Entity" },
          { key: "subject_record_id", label: "Subject Record" },
          { key: "assigned_to", label: "Assigned To" },
          { key: "assigned_by", label: "Assigned By" },
          { key: "status", label: "Status" },
        ]}
      />
      <RecordEdit
        entityKey="assignment"
        recordId={recordId}
        schema={assignmentSchema}
        visibleFields={["status"]}
        heading="Change status"
        submitLabel="Change status"
      />
    </section>
  );
}
''',
        "TaskDetail": '''export function TaskDetail({ recordId = "", title = "Task" }) {
  return (
    <section>
      <AdminRecordDetail
        entityKey="platform_task"
        recordId={recordId}
        title={title}
        fields={[
          { key: "title", label: "Title" },
          { key: "description", label: "Description" },
          { key: "status", label: "Status" },
          { key: "due_date", label: "Due Date" },
          { key: "subject_entity_key", label: "Subject Entity" },
          { key: "subject_record_id", label: "Subject Record" },
        ]}
      />
      <RecordEdit
        entityKey="platform_task"
        recordId={recordId}
        schema={platform_taskSchema}
        visibleFields={["status"]}
        heading="Change status"
        submitLabel="Change status"
      />
    </section>
  );
}
''',
    }
    for name, body in react_fns.items():
        react_source = _replace_function(react_source, name, body)
    for spec in BLOCKS:
        export = f"export function {spec['status']}"
        if export not in react_source:
            react_source += f'''
{export}({{ recordId = "" }}) {{
  return (
    <RecordEdit
      entityKey="{spec["entity_key"]}"
      recordId={{recordId}}
      schema={{{spec["schema_file"]}Schema}}
      visibleFields={{["status"]}}
      heading="{spec["heading"]}"
      submitLabel="{spec["heading"]}"
    />
  );
}}
'''
    write(react_blocks, react_source)

    crm_react = ROOT / "boilerplates/react_app/src/components/starter/crm-blocks.jsx"
    crm_text = crm_react.read_text(encoding="utf-8")
    if "export function PipelineStatusEdit" not in crm_text:
        crm_text += '''
export function PipelineStatusEdit({recordId}) {
 return <RecordEdit entityKey="lead" recordId={recordId}
 schema={leadSchema} visibleFields={["status"]} heading="Change pipeline stage" submitLabel="Change stage" />;
}
'''
        write(crm_react, crm_text)

    html_blocks = ROOT / "boilerplates/html/js/starter-blocks.js"
    html_source = html_blocks.read_text(encoding="utf-8")
    schema_const = ""
    for key in ("platform_task", "case_record", "assignment"):
        const_name = f"{key}Schema"
        if const_name not in html_source:
            schema_const += (
                f"const {const_name} = "
                + json.dumps({"fields": schemas[key]})
                + ";\n"
            )
    if schema_const:
        html_source = html_source.replace(
            "export function mountCaseTable",
            schema_const + "export function mountCaseTable",
            1,
        )
    html_fns = {
        "mountCaseDetail": _html_combined(BLOCKS[1]),
        "mountAssignmentDetail": _html_combined(BLOCKS[2]),
        "mountTaskDetail": _html_combined(BLOCKS[0]),
    }
    for name, body in html_fns.items():
        html_source = _replace_function(html_source, name, body)
    for spec in BLOCKS:
        export = f"export function mount{spec['status']}"
        if export not in html_source:
            html_source += f'''
{export}(root, props = {{}}) {{
  return mountRecordEdit(root, {{
    ...props,
    entityKey: "{spec["entity_key"]}",
    schema: {spec["schema_file"]}Schema,
    visibleFields: ["status"],
    heading: "{spec["heading"]}",
    submitLabel: "{spec["heading"]}",
  }});
}}
'''
    write(html_blocks, html_source)

    html_crm = ROOT / "boilerplates/html/js/crm-blocks.js"
    crm_html = html_crm.read_text(encoding="utf-8")
    if "export function mountPipelineStatusEdit" not in crm_html:
        crm_html += '''
export function mountPipelineStatusEdit(root, props={}) {
 return mountRecordEdit(root,{...props,entityKey:"lead",schema:leadSchema,visibleFields:["status"],heading:"Change pipeline stage",submitLabel:"Change stage"});
}
'''
        write(html_crm, crm_html)

    impls = {
        "nuxt_app": lambda component: f"components/starter/blocks/{component}.vue",
        "react_app": lambda component: (
            "src/components/starter/crm-blocks.jsx#PipelineStatusEdit"
            if component == "PipelineStatusEdit"
            else f"src/components/starter/blocks.jsx#{component}"
        ),
        "html": lambda component: (
            "js/crm-blocks.js#mountPipelineStatusEdit"
            if component == "PipelineStatusEdit"
            else f"js/starter-blocks.js#mount{component}"
        ),
    }
    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)
        for host in hosts["hosts"]:
            block, slot = host["block"], host["slot"]
            if slot != "status":
                continue
            if block == "crm.pipeline":
                host["implementation"] = impls[framework]("PipelineStatusEdit")
                continue
            spec = next((item for item in BLOCKS if item["block"] == block), None)
            if spec:
                host["implementation"] = impls[framework](spec["status"])
        hosts["hosts"] = [host for host in hosts["hosts"] if host.get("implementation")]
        write(path, json.dumps(hosts, indent=2) + "\n")
    print("12D status-only record.edit hosts materialized")


if __name__ == "__main__":
    main()
