"""DentalComplianceOS CLI — scan, log, report, and prepare for dental compliance inspections.

Usage:
    dentalcomplianceos scan <path> --framework osha_dental
    dentalcomplianceos status [--framework osha_dental]
    dentalcomplianceos log-sterilization --autoclave Statim-1 ...
    dentalcomplianceos log-radiation --equipment Dexis-Op1 ...
    dentalcomplianceos inspection-prep --state CA --practice-type solo_gp
    dentalcomplianceos fix [--framework osha_dental]
    dentalcomplianceos report [--framework osha_dental] [--format json]
    dentalcomplianceos serve   # Start MCP server
"""

from __future__ import annotations

import json
import sys
from pathlib import Path

import click

from .frameworks import FRAMEWORKS, FRAMEWORK_NAMES
from .store import DentalComplianceStore
from .types import SterilizationRecord, RadiationRecord


FRAMEWORK_CHOICES = list(FRAMEWORKS.keys())
PRACTICE_TYPES = ["solo_gp", "group", "ortho", "perio", "oral_surgery", "pedo", "endo", "prostho", "dso"]
STATES = ["CA", "TX", "FL", "NY", "PA", "IL", "OH", "GA", "NC", "MI"]


def _get_store(db: str | None = None) -> DentalComplianceStore:
    """Create a store instance."""
    return DentalComplianceStore(db)


@click.group()
@click.version_option(version="0.1.0", prog_name="DentalComplianceOS")
def main() -> None:
    """DentalComplianceOS -- Dental-Specific Compliance Automation.

    Scans dental practices against OSHA, CDC, HIPAA, radiation safety,
    state board regulations, and sterilization protocols. Tracks compliance,
    logs sterilization and radiation data, and generates audit-ready reports.
    """
    pass


@main.command()
@click.argument("target", type=click.Path(exists=True))
@click.option("--framework", "-f", type=click.Choice(FRAMEWORK_CHOICES), required=True,
              help="Dental compliance framework to scan against")
@click.option("--practice-type", "-p", type=click.Choice(PRACTICE_TYPES), default="solo_gp",
              help="Type of dental practice")
@click.option("--state", "-s", type=click.Choice(STATES), default=None,
              help="State for state-specific regulations")
@click.option("--db", default=None, help="Custom database path")
@click.option("--json-output", is_flag=True, help="Output raw JSON")
def scan(target: str, framework: str, practice_type: str, state: str | None,
         db: str | None, json_output: bool) -> None:
    """Scan a practice's documentation against a compliance framework."""
    from .server import _run_scan

    store = _get_store(db)
    try:
        result = _run_scan(target, framework, store, practice_type, state or "")

        if "error" in result:
            click.secho(f"Error: {result['error']}", fg="red")
            sys.exit(1)

        if json_output:
            click.echo(json.dumps(result, indent=2))
            return

        fw_name = FRAMEWORK_NAMES.get(framework, framework)
        score = result.get("score", 0)
        color = "green" if score >= 80 else "yellow" if score >= 60 else "red"

        click.echo()
        click.secho(f"  {fw_name} Compliance Scan", fg="blue", bold=True)
        click.echo(f"  Target: {result.get('practice_type', '')} practice")
        if state:
            click.echo(f"  State: {state}")
        click.echo(f"  Scan ID: {result.get('scan_id', '')}")
        click.echo()
        click.secho(f"  Score: {score:.1f}%", fg=color, bold=True)
        click.echo(
            f"  Checks: {result.get('compliant', 0)} compliant / "
            f"{result.get('non_compliant', 0)} non-compliant / "
            f"{result.get('total_checks', 0)} total"
        )
        click.echo()

        findings = result.get("findings", [])
        non_compliant = [
            f for f in findings
            if f.get("status") in ("non_compliant", "unknown")
        ]

        if non_compliant:
            by_sev: dict[str, list] = {}
            for f in non_compliant:
                sev = f.get("severity", "info")
                by_sev.setdefault(sev, []).append(f)

            sev_colors = {
                "critical": "red", "high": "red",
                "medium": "yellow", "low": "cyan", "info": "white",
            }

            for sev in ["critical", "high", "medium", "low", "info"]:
                items = by_sev.get(sev, [])
                if not items:
                    continue
                click.secho(
                    f"  [{sev.upper()}] ({len(items)} findings)",
                    fg=sev_colors.get(sev, "white"), bold=True,
                )
                for f in items:
                    click.echo(f"    - [{f.get('check_id', '')}] {f.get('detail', '')}")
                click.echo()

            click.secho(
                f"  Run 'dentalcomplianceos fix -f {framework}' for corrective action plans.",
                fg="yellow",
            )
        else:
            click.secho("  All checks compliant!", fg="green", bold=True)

        click.echo()
    finally:
        store.close()


@main.command()
@click.option("--framework", "-f", type=click.Choice(FRAMEWORK_CHOICES), default=None,
              help="Specific framework (omit for all)")
@click.option("--db", default=None)
def status(framework: str | None, db: str | None) -> None:
    """Show current compliance posture."""
    store = _get_store(db)
    try:
        if framework:
            scan_data = store.get_latest_scan(framework)
            if not scan_data:
                click.secho(
                    f"No scan results for {FRAMEWORK_NAMES.get(framework, framework)}.",
                    fg="yellow",
                )
                click.echo(f"Run: dentalcomplianceos scan <path> -f {framework}")
                return

            fw_name = FRAMEWORK_NAMES.get(framework, framework)
            score = scan_data.get("score", 0)
            color = "green" if score >= 80 else "yellow" if score >= 60 else "red"

            click.echo()
            click.secho(f"  {fw_name} Status", fg="blue", bold=True)
            click.echo(f"  Last scan: {scan_data.get('timestamp', '')[:19]}")
            click.secho(f"  Score: {score:.1f}%", fg=color, bold=True)
            click.echo(
                f"  Compliant: {scan_data.get('compliant', 0)} / "
                f"{scan_data.get('total_checks', 0)}"
            )
            click.echo()
        else:
            summaries = store.get_all_scan_summaries()
            if not summaries:
                click.secho("No scan results yet.", fg="yellow")
                click.echo("Run: dentalcomplianceos scan <path> -f <framework>")
                return

            click.echo()
            click.secho("  Dental Compliance Posture", fg="blue", bold=True)
            click.echo()
            for s in summaries:
                fw_name = FRAMEWORK_NAMES.get(s["framework"], s["framework"])
                score = s.get("score", 0)
                color = "green" if score >= 80 else "yellow" if score >= 60 else "red"
                click.echo(f"  {fw_name:45s} ", nl=False)
                click.secho(f"{score:.0f}%", fg=color, bold=True)

            click.echo()
    finally:
        store.close()


@main.command("log-sterilization")
@click.option("--autoclave", required=True, help="Autoclave ID (e.g. Statim-1)")
@click.option("--cycle-type", type=click.Choice(["gravity", "pre_vacuum", "flash"]), required=True)
@click.option("--temp", type=float, required=True, help="Temperature in Fahrenheit")
@click.option("--pressure", type=float, required=True, help="Pressure in PSI")
@click.option("--duration", type=float, required=True, help="Duration in minutes")
@click.option("--bio", type=click.Choice(["pass", "fail", "pending", "not_tested"]),
              required=True, help="Biological indicator result")
@click.option("--chem", type=click.Choice(["pass", "fail"]), required=True,
              help="Chemical indicator result")
@click.option("--load", default="", help="Load contents description")
@click.option("--operator", default="", help="Operator name")
@click.option("--notes", default="", help="Additional notes")
@click.option("--db", default=None)
def log_sterilization(
    autoclave: str, cycle_type: str, temp: float, pressure: float,
    duration: float, bio: str, chem: str, load: str, operator: str,
    notes: str, db: str | None,
) -> None:
    """Log a sterilization cycle."""
    store = _get_store(db)
    try:
        record = SterilizationRecord(
            autoclave_id=autoclave,
            cycle_type=cycle_type,
            temperature=temp,
            pressure=pressure,
            duration_minutes=duration,
            biological_indicator=bio,
            chemical_indicator=chem,
            load_contents=load,
            operator=operator,
            notes=notes,
        )
        log_id = store.log_sterilization(record)
        click.secho(f"  Sterilization cycle logged (ID: {log_id})", fg="green")

        if bio == "fail":
            click.secho(
                "\n  CRITICAL: Biological indicator FAILED!",
                fg="red", bold=True,
            )
            click.echo("  1. Remove autoclave from service immediately")
            click.echo("  2. Recall all items since last negative BI")
            click.echo("  3. Re-sterilize all recalled items")
            click.echo("  4. Run 3 consecutive BIs — all must be negative before resuming")
            click.echo()

        if chem == "fail":
            click.secho(
                "\n  WARNING: Chemical indicator failed.",
                fg="yellow", bold=True,
            )
            click.echo("  Do not use instruments from this load. Re-clean and re-sterilize.")
            click.echo()
    finally:
        store.close()


@main.command("log-radiation")
@click.option("--equipment", required=True, help="Equipment ID (e.g. Dexis-Op1)")
@click.option("--type", "log_type",
              type=click.Choice(["exposure", "qa_test", "equipment_check", "lead_apron_check"]),
              required=True, help="Type of radiation log entry")
@click.option("--details", required=True, help="Event description")
@click.option("--result", default="", help="Result or outcome")
@click.option("--operator", default="", help="Operator name")
@click.option("--db", default=None)
def log_radiation(
    equipment: str, log_type: str, details: str, result: str,
    operator: str, db: str | None,
) -> None:
    """Log a radiation event (exposure, QA test, lead apron check, etc.)."""
    store = _get_store(db)
    try:
        record = RadiationRecord(
            equipment_id=equipment,
            log_type=log_type,
            details=details,
            result=result,
            operator=operator,
        )
        log_id = store.log_radiation(record)
        click.secho(f"  Radiation event logged (ID: {log_id})", fg="green")

        if log_type == "lead_apron_check" and result == "fail":
            click.secho(
                "\n  WARNING: Lead apron inspection FAILED!",
                fg="red", bold=True,
            )
            click.echo("  Remove from service immediately. Replace before next patient use.")
            click.echo()

        if log_type == "qa_test" and result == "fail":
            click.secho(
                "\n  WARNING: QA test FAILED!",
                fg="yellow", bold=True,
            )
            click.echo("  Remove equipment from clinical use until serviced/calibrated.")
            click.echo()
    finally:
        store.close()


@main.command("inspection-prep")
@click.option("--state", "-s", type=click.Choice(STATES), required=True,
              help="State for state-specific requirements")
@click.option("--practice-type", "-p", type=click.Choice(PRACTICE_TYPES), default="solo_gp",
              help="Type of dental practice")
@click.option("--json-output", is_flag=True, help="Output raw JSON")
def inspection_prep(state: str, practice_type: str, json_output: bool) -> None:
    """Generate inspection preparation checklist."""
    from .server import _generate_inspection_checklist

    checklist = _generate_inspection_checklist(state, practice_type)

    if json_output:
        click.echo(json.dumps(checklist, indent=2))
        return

    click.echo()
    click.secho(
        f"  Inspection Prep Checklist — {state} / {practice_type}",
        fg="blue", bold=True,
    )
    click.echo(f"  Total items: {checklist['total_items']}")
    click.echo()

    for fw_name, items in checklist.get("frameworks", {}).items():
        click.secho(f"  {fw_name} ({len(items)} items)", fg="white", bold=True)
        for item in items:
            sev = item.get("severity", "medium")
            sev_colors = {"critical": "red", "high": "red", "medium": "yellow", "low": "cyan"}
            color = sev_colors.get(sev, "white")
            click.echo(f"    ", nl=False)
            click.secho(f"[{sev[0].upper()}]", fg=color, nl=False)
            click.echo(f" [{item['check_id']}] {item['item']}")
        click.echo()


@main.command()
@click.option("--framework", "-f", type=click.Choice(FRAMEWORK_CHOICES), default=None)
@click.option("--db", default=None)
def fix(framework: str | None, db: str | None) -> None:
    """Generate corrective action plans for non-compliant findings."""
    from .server import _generate_corrective_actions

    store = _get_store(db)
    try:
        findings = store.get_non_compliant_findings(framework)
        if not findings:
            click.secho("  No non-compliant findings.", fg="green")
            if framework:
                click.echo(f"  Run scan first: dentalcomplianceos scan <path> -f {framework}")
            return

        actions = _generate_corrective_actions(findings)

        click.echo()
        click.secho(
            f"  Corrective Action Plan ({len(actions)} items)",
            fg="blue", bold=True,
        )
        click.echo()

        for i, action in enumerate(actions, 1):
            sev = action["severity"]
            sev_colors = {"critical": "red", "high": "red", "medium": "yellow", "low": "cyan"}
            color = sev_colors.get(sev, "white")

            click.echo(f"  {i}. ", nl=False)
            click.secho(f"[{sev.upper()}]", fg=color, nl=False)
            click.echo(f" [{action['check_id']}] {action['title']}")
            click.echo(f"     Timeline: {action['timeline']}")
            click.echo(f"     Action: {action['corrective_action']}")
            click.echo()

    finally:
        store.close()


@main.command()
@click.option("--framework", "-f", type=click.Choice(FRAMEWORK_CHOICES), default=None)
@click.option("--format", "fmt", type=click.Choice(["markdown", "json"]), default="markdown")
@click.option("--output", "-o", default=None, help="Output file path")
@click.option("--db", default=None)
def report(framework: str | None, fmt: str, output: str | None, db: str | None) -> None:
    """Generate an audit-ready compliance report."""
    from .server import _generate_report

    store = _get_store(db)
    try:
        report_text = _generate_report(store, framework, fmt)

        if output:
            Path(output).write_text(report_text, encoding="utf-8")
            click.secho(f"  Report saved to {output}", fg="green")
        else:
            click.echo(report_text)
    finally:
        store.close()


@main.command()
@click.option("--db", default=None)
def serve(db: str | None) -> None:
    """Start the DentalComplianceOS MCP server (stdio)."""
    import asyncio
    from .server import create_server
    from mcp.server.stdio import stdio_server

    async def _run() -> None:
        server = create_server(db)
        async with stdio_server() as (read_stream, write_stream):
            await server.run(
                read_stream, write_stream, server.create_initialization_options()
            )

    asyncio.run(_run())


if __name__ == "__main__":
    main()
