#!/usr/bin/env python3
"""File-based TAC Product Factory MVP."""
from __future__ import annotations

import json
import re
import sys
from datetime import datetime, timezone
from pathlib import Path

ROOT = Path(__file__).resolve().parent
CATALOG = ROOT / "catalog.json"
EVENT_DIR = ROOT / ".events"
PRODUCTS_DIR = ROOT / "generated"
DASHBOARD = ROOT / "DASHBOARD.md"
PLANS_DIR = ROOT.parent / "plans"
RECEIPTS_DIR = ROOT / "receipts"
RSI_EVIDENCE_RECEIPT = "packages/pi-real-engineering/docs/receipts/rsi-proof-20260619T093724Z.md"
LOCAL_RSI_EVIDENCE_RECEIPT = "products/receipts/rsi-proof-20260619T093724Z.md"
RSI_DECISION = "healthy_but_autopatch_unproven"
RSI_CLAIM = (
    "Factory RSI is healthy at 65/65 with cron, skill_health, factory_watcher, "
    "and deploy_route present; auto_patch_proven=false until a degraded-skill "
    "recovery receipt exists; rsi_canary evidence is tracked separately"
)
FACTORY_STATE = {
    "factory_phase": 4,
    "agent_rsi_phases": "A-D operational",
    "containers": 25,
    "agents": 6,
    "infra": 14,
    "monitoring_deploy": 5,
    "skills": 63,
    "latest_score": "65/65",
    "factory_watcher": True,
    "deploy_route_present": True,
    "root_commit": "55bdf3f",
    "hermes_agent_commit": "fd3053b",
}
LOOP_ENGINEERING = {
    "agent_loop": "ADW phases run tools until product task completion",
    "verification_loop": "plan validation, pytest checks, verifier_result, and receipts gate readiness",
    "event_driven_loop": "GitHub webhooks, cron skill_health, event JSONL, and dashboard refresh trigger work",
    "hill_climbing_loop": "skill_health/SkillOpt can propose signed action patches; guarded by receipts and rollback",
}


def slugify(text: str) -> str:
    slug = re.sub(r"[^a-zA-Z0-9]+", "-", text.lower()).strip("-")
    return slug[:60] or "product"


def load_catalog() -> list[dict]:
    return json.loads(CATALOG.read_text(encoding="utf-8")) if CATALOG.exists() else []


def log_event(kind: str, **data) -> Path:
    EVENT_DIR.mkdir(parents=True, exist_ok=True)
    path = EVENT_DIR / f"{datetime.now(timezone.utc).date().isoformat()}.jsonl"
    event = {"ts": datetime.now(timezone.utc).isoformat(), "kind": kind, **data}
    with path.open("a", encoding="utf-8") as f:
        f.write(json.dumps(event, ensure_ascii=False) + "\n")
    return path


def living_plan_metadata(product_id: str) -> dict:
    return {
        "plan_id": product_id,
        "plan_ref": f"plans/{product_id}/plan.md",
        "format": ["markdown", "html-first", "append-only-amendments"],
        "required_sections": ["purpose", "problem", "solution", "files", "phases", "validation", "references", "notes"],
        "deploy_endpoint": "git-proxy:8099/deploy",
        "legacy_internal": ["deploy-webhook:8098"],
        "rsi_decision": RSI_DECISION,
        "auto_patch_proven": False,
        "rsi_canary_recovery_evidence": True,
        "rsi_evidence_receipt": RSI_EVIDENCE_RECEIPT,
        "local_rsi_evidence_receipt": LOCAL_RSI_EVIDENCE_RECEIPT,
        "rsi_claim": RSI_CLAIM,
        "factory_state": FACTORY_STATE,
        "loop_engineering": LOOP_ENGINEERING,
    }


def render_plan_md(product_id: str, purpose: str) -> str:
    return f"""---
product_id: {product_id}
purpose: {purpose}
references:
  - products/AGENT_PRODUCTS.md
---

## Purpose
{purpose}

## Problem
Define the product problem before build.

## Solution
Build the smallest agent-run product that satisfies the plan.

## Files
- products/generated/{product_id}/spec.json
- products/generated/{product_id}/README.md

## Phases
- [ ] Plan
- [ ] Build
- [ ] Test
- [ ] Verify
- [ ] Signed deploy

## Validation
- uv run --with pytest pytest -q

## References
- products/AGENT_PRODUCTS.md

## Notes
Plan F3 living artifact. Amendments append below.
"""


def render_plan_html(product_id: str, purpose: str) -> str:
    return f"""<section data-plan=\"{product_id}\">
  <h1>{product_id}</h1>
  <h2>Purpose</h2><p>{purpose}</p>
  <h2>Problem</h2><p>Define the product problem before build.</p>
  <h2>Solution</h2><p>Build the smallest agent-run product that satisfies the plan.</p>
  <h2>Files</h2><p>See plan.md.</p>
  <h2>Phases</h2><ul><li>Plan</li><li>Build</li><li>Test</li><li>Verify</li><li>Signed deploy</li></ul>
  <h2>Validation</h2><p>uv run --with pytest pytest -q</p>
  <h2>References</h2><p>products/AGENT_PRODUCTS.md</p>
  <h2>Notes</h2><p>Plan F3 living artifact.</p>
</section>
"""


def create_plan(product_id: str, purpose: str, overwrite: bool = False) -> Path:
    path = PLANS_DIR / product_id
    path.mkdir(parents=True, exist_ok=True)
    md = path / "plan.md"
    html = path / "plan.html"
    if md.exists() and not overwrite:
        raise FileExistsError(f"plan already exists: {md}")
    md.write_text(render_plan_md(product_id, purpose), encoding="utf-8")
    html.write_text(render_plan_html(product_id, purpose), encoding="utf-8")
    return md


def validate_product_plan(product_id: str) -> dict:
    from products.plan_validator import validate_plan
    return validate_plan(PLANS_DIR / product_id / "plan.md", strict=True)


def run_adw_pipeline(product_id: str, zte: bool = False) -> dict:
    try:
        from adw_modules.adw_pipeline import run_pipeline
        return run_pipeline(product_id, zte=zte)
    except Exception as exc:
        return {"ok": False, "error": str(exc), "phases": []}


def latest_event(kind: str | None = None) -> dict | None:
    if not EVENT_DIR.exists():
        return None
    for path in sorted(EVENT_DIR.glob("*.jsonl"), reverse=True):
        for line in reversed(path.read_text(encoding="utf-8").splitlines()):
            event = json.loads(line)
            if kind is None or event.get("kind") == kind:
                return event
    return None


def write_receipt(product_id: str, status: str, checks_ok: bool, plan_ok: bool, deploy_route: str) -> Path:
    RECEIPTS_DIR.mkdir(parents=True, exist_ok=True)
    ts = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
    path = RECEIPTS_DIR / f"{ts}-{product_id}.json"
    receipt = {
        "product_id": product_id,
        "status": status,
        "checks_ok": checks_ok,
        "plan_ok": plan_ok,
        "deploy_route": deploy_route,
        "rsi_decision": RSI_DECISION,
        "auto_patch_proven": False,
        "rsi_canary_recovery_evidence": True,
        "rsi_evidence_receipt": RSI_EVIDENCE_RECEIPT,
        "local_rsi_evidence_receipt": LOCAL_RSI_EVIDENCE_RECEIPT,
        "rsi_claim": RSI_CLAIM,
        "factory_state": FACTORY_STATE,
        "loop_engineering": LOOP_ENGINEERING,
    }
    path.write_text(json.dumps(receipt, indent=2, ensure_ascii=False), encoding="utf-8")
    return path


def create_product(idea: str, overwrite: bool = False) -> dict:
    product_id = slugify(idea)
    path = PRODUCTS_DIR / product_id
    if path.exists() and not overwrite:
        raise FileExistsError(f"product already exists: {product_id}")

    event_path = log_event("idea_received", product_id=product_id, idea=idea)
    path.mkdir(parents=True, exist_ok=True)
    plan_path = create_plan(product_id, idea, overwrite=overwrite)
    plan_check = validate_product_plan(product_id)
    spec = {
        "id": product_id,
        "idea": idea,
        "spine": ["plan", "build", "test", "verify", "signed-deploy", "observe", "improve"],
        "skills": [
            "agent-chain",
            "agent-team",
            "verifier-builder",
            "confidence-ladder",
            "damage-control",
            "tool-call-tracer",
            "experiment-loop",
            "tilldone",
        ],
        "agents": ["planner", "builder", "reviewer", "executor", "tracker"],
        "deploy_actions": ["patch_skill_from_pr"],
        "status": "specified",
        "living_plan": living_plan_metadata(product_id),
        "plan_valid": plan_check["ok"],
        "singularity": {
            "class": 3,
            "grade": 3,
            "layer": "orchestrator-adw",
            "principle": "build the system that builds the system",
        },
    }
    (path / "spec.json").write_text(json.dumps(spec, indent=2, ensure_ascii=False), encoding="utf-8")
    (path / "README.md").write_text(render_readme(spec), encoding="utf-8")
    log_event("product_spec_created", product_id=product_id, idea=idea, spec=str(path / "spec.json"))
    log_event(
        "plan_written",
        product_id=product_id,
        plan=str(plan_path),
        plan_id=product_id,
        plan_ref=living_plan_metadata(product_id)["plan_ref"],
        plan_ok=plan_check["ok"],
    )
    log_event("adw_pipeline_started", product_id=product_id)
    pipeline_result = run_adw_pipeline(product_id)
    checks = ["plan", "build", "test", "review", "document", "ship"]
    checks_ok = bool(pipeline_result.get("ok")) and plan_check["ok"]
    log_event(
        "checks_run",
        product_id=product_id,
        checks=checks,
        checks_ok=checks_ok,
        plan_ok=plan_check["ok"],
        plan_id=product_id,
        plan_ref=living_plan_metadata(product_id)["plan_ref"],
    )
    log_event("verifier_result", product_id=product_id, ok=checks_ok)
    deploy_route = "git-proxy:8099/deploy"
    log_event("deploy_action_requested", product_id=product_id, action="patch_skill_from_pr", route=deploy_route)
    status = "ready" if checks_ok else "needs_attention"
    receipt_path = write_receipt(product_id, status, checks_ok, plan_check["ok"], deploy_route)
    log_event("outcome", product_id=product_id, status=status, receipt=str(receipt_path))
    render_dashboard()
    return {"product_id": product_id, "path": str(path), "plan": str(plan_path), "receipt": str(receipt_path), "event_log": str(event_path)}


def render_readme(spec: dict) -> str:
    return f"""# {spec['id']}

Idea: {spec['idea']}

## Agent spine

`{' -> '.join(spec['spine'])}`

## Skills

{chr(10).join(f"- `{s}`" for s in spec['skills'])}

## Deploy

Only signed factory actions are allowed:

{chr(10).join(f"- `{a}`" for a in spec['deploy_actions'])}

## Living plan

Plan ref: `{spec['living_plan']['plan_ref']}`

Deploy endpoint: `{spec['living_plan']['deploy_endpoint']}`

RSI claim: {spec['living_plan']['rsi_claim']}.

RSI evidence receipt: `{spec['living_plan']['rsi_evidence_receipt']}`.
Local evidence mirror: `{spec['living_plan']['local_rsi_evidence_receipt']}`.

## Factory state

{chr(10).join(f"- `{k}`: {v}" for k, v in spec['living_plan']['factory_state'].items())}

## Loop engineering

{chr(10).join(f"- `{k}`: {v}" for k, v in spec['living_plan']['loop_engineering'].items())}

## Singularity ladder

Class {spec['singularity']['class']}, Grade {spec['singularity']['grade']}: `{spec['singularity']['layer']}`

Principle: {spec['singularity']['principle']}.
"""


def render_ladder() -> str:
    rows = ["| Product | Class | Grade | Agentic layer |", "|---|---:|---:|---|"]
    for item in load_catalog():
        rows.append(
            f"| {item['name']} | {item.get('singularity_class', '')} | "
            f"{item.get('singularity_grade', '')} | {item.get('agentic_layer', '')} |"
        )
    return "\n".join(rows)


def render_dashboard() -> str:
    rows = [
        "| Product | Price | Status | Class | Grade | Agentic layer | Skills | Deploy actions |",
        "|---|---:|---|---:|---:|---|---:|---|",
    ]
    for item in load_catalog():
        rows.append(
            f"| {item['name']} | ${item.get('price', 0)} | {item.get('status', '')} | "
            f"{item.get('singularity_class', '')} | {item.get('singularity_grade', '')} | "
            f"{item.get('agentic_layer', '')} | {len(item.get('skills', []))} | "
            f"{', '.join(item.get('deploy_actions', [])) or 'none'} |"
        )
    generated = sorted((PRODUCTS_DIR).glob("*/spec.json")) if PRODUCTS_DIR.exists() else []
    last_check = latest_event("checks_run")
    outcome = latest_event("outcome")
    last_check_text = (
        f"- `{last_check['product_id']}`: checks_ok=`{last_check.get('checks_ok')}` plan_ok=`{last_check.get('plan_ok')}` checks={', '.join(last_check.get('checks', []))}"
        if last_check else "- No checks logged yet"
    )
    readiness_text = (
        f"- `{outcome['product_id']}`: {outcome.get('status', 'unknown')} via signed `git-proxy:8099/deploy`; receipt={outcome.get('receipt', 'missing')}"
        if outcome else "- No outcome logged yet"
    )
    text = f"""# TAC Products Dashboard

{chr(10).join(rows)}

## Generated products

{chr(10).join(f'- `{p.parent.name}`' for p in generated) or '- none yet'}

## Last check

{last_check_text}

## Deploy readiness

{readiness_text}

## Plan status

- Plans live in `plans/<product_id>/plan.md` and must validate before build/deploy.
- Amendments are append-only via `## Amendment <UTC timestamp>`.

## Open risks

- Do not overclaim arbitrary self-improvement; only verified canary/receipts belong here.
- Legacy direct `:8098` deploy-webhook is internal/stale for guarded deploy; use `:8099/deploy`.

## Current factory truth

- RSI status: live factory reports {FACTORY_STATE['latest_score']} healthy, cron + skill_health present, factory_watcher active, deploy_route present, and `auto_patch_proven=false`; `rsi_canary` recovery evidence is linked at `{RSI_EVIDENCE_RECEIPT}` and mirrored at `{LOCAL_RSI_EVIDENCE_RECEIPT}`.
- Engine factory memory: {FACTORY_STATE['containers']} containers, {FACTORY_STATE['agents']} agents, {FACTORY_STATE['infra']} infra, {FACTORY_STATE['monitoring_deploy']} monitoring/deploy, {FACTORY_STATE['skills']} skills.
- Commit evidence: root `{FACTORY_STATE['root_commit']}`, hermes-agent `{FACTORY_STATE['hermes_agent_commit']}`.
- Deploy path must use signed actions through git-proxy `:8099/deploy`, not raw shell or direct legacy `:8098` deploy.

## Loop engineering

- Loop 1 agent: ADW planner/builder/tester/reviewer/deployer phases run tools until done.
- Loop 2 verification: plan validation, pytest, verifier events, and receipts gate readiness.
- Loop 3 event-driven: GitHub webhooks, cron `skill_health`, JSONL events, and dashboard refresh trigger work.
- Loop 4 hill-climbing: SkillOpt/skill_health can request signed patches, but broader auto-patch autonomy stays unproven without degraded-skill recovery receipts.

## Next action

```bash
python products/product_factory.py "agent-powered customer support triage product"
python products/product_factory.py ladder
uv run --with pytest pytest -q
```
"""
    DASHBOARD.write_text(text, encoding="utf-8")
    return text


def main(argv: list[str] | None = None) -> int:
    argv = argv or sys.argv[1:]
    if argv == ["dashboard"]:
        print(render_dashboard())
        return 0
    if argv == ["ladder"]:
        print(render_ladder())
        return 0
    if not argv:
        print("usage: python products/product_factory.py '<product idea>' | dashboard | ladder", file=sys.stderr)
        return 2
    print(json.dumps(create_product(" ".join(argv)), indent=2))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
