"""Practice Scanner — scans practice documentation and policies for compliance.

Looks for policy documents, training records, logs, and other evidence
in a practice's documentation directory.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from ..types import ComplianceFinding, ComplianceStatus, Severity


# Map file/directory names to check IDs they can satisfy
_EVIDENCE_MAP: dict[str, list[str]] = {
    "exposure_control_plan": ["BBP-1.1", "BBP-1.2", "BBP-1.3", "BBP-1.4"],
    "exposure-control-plan": ["BBP-1.1", "BBP-1.2", "BBP-1.3", "BBP-1.4"],
    "hazcom": ["HAZCOM-1.1", "HAZCOM-1.2", "HAZCOM-1.3"],
    "hazard_communication": ["HAZCOM-1.1", "HAZCOM-1.2", "HAZCOM-1.3"],
    "sds": ["HAZCOM-1.2"],
    "safety_data_sheets": ["HAZCOM-1.2"],
    "ppe": ["PPE-1.1", "PPE-1.2"],
    "training": ["TRAIN-1.1", "TRAIN-1.2", "TRAIN-1.3", "TRAIN-1.4", "TRAIN-1.5"],
    "training_records": ["TRAIN-1.1", "TRAIN-1.2", "TRAIN-1.3", "TRAIN-1.4"],
    "emergency_action_plan": ["EAP-1.1", "EAP-1.2"],
    "emergency": ["EAP-1.1", "EAP-1.4"],
    "infection_control": ["HH-1.1", "SURF-1.1", "INST-1.2", "HP-1.1"],
    "hand_hygiene": ["HH-1.1", "HH-1.2"],
    "sterilization": ["AUTO-1.1", "BIO-1.1", "CHEM-1.1"],
    "sterilization_log": ["AUTO-1.1", "AUTO-1.2"],
    "spore_test": ["BIO-1.1", "BIO-1.3"],
    "biological_indicator": ["BIO-1.1", "BIO-1.3"],
    "hipaa": ["PHI-1.1", "RISK-1.1", "ACCESS-1.1", "BAA-1.1"],
    "privacy": ["PHI-1.1", "SOCIAL-1.1"],
    "risk_assessment": ["RISK-1.1", "RISK-1.2"],
    "baa": ["BAA-1.1", "BAA-1.2", "BAA-1.3", "BAA-1.4"],
    "business_associate": ["BAA-1.1", "BAA-1.2", "BAA-1.3"],
    "breach": ["BREACH-1.1", "BREACH-1.2"],
    "radiation": ["XREG-1.1", "ALARA-1.1", "TECH-1.1"],
    "radiation_safety": ["XREG-1.1", "ALARA-1.1", "ALARA-1.2"],
    "xray": ["XREG-1.1", "TECH-1.1", "QA-1.1"],
    "lead_apron": ["LEAD-1.1"],
    "technique_chart": ["TECH-1.1", "TECH-1.2"],
    "waterline": ["DUWL-1.1", "DUWL-1.2"],
    "duwl": ["DUWL-1.1", "DUWL-1.2", "DUWL-1.3"],
    "sedation": ["SED-1.1", "SED-1.2", "SED-1.3"],
    "ce_records": ["CE-1.1", "CE-1.2", "CE-1.3"],
    "continuing_education": ["CE-1.1", "CE-1.2", "CE-1.3"],
    "license": ["LIC-1.1", "LIC-1.2", "LIC-1.3"],
    "compliance_checklist": [],
    "osha_log": ["RECORD-1.1"],
    "sharps_log": ["BBP-4.2"],
    "chemical_inventory": ["HAZCOM-1.3"],
}


class PracticeScanner:
    """Scans a practice's documentation directory for compliance evidence."""

    def __init__(self, target_path: Path) -> None:
        self.target_path = target_path

    def scan(self, checks: list[dict[str, Any]]) -> list[ComplianceFinding]:
        """Scan the target directory against the given checks.

        For each check, look for evidence files/directories that would
        satisfy the requirement. If found, mark as compliant; if not,
        mark as non_compliant.

        Args:
            checks: List of check definitions to evaluate.

        Returns:
            List of findings for checks that are non-compliant.
        """
        findings: list[ComplianceFinding] = []

        # Build set of check IDs satisfied by existing evidence
        satisfied_checks: set[str] = set()

        if self.target_path.exists() and self.target_path.is_dir():
            satisfied_checks = self._find_evidence(self.target_path)

        # Also check for a compliance status JSON
        status_file = self.target_path / "compliance_status.json"
        if status_file.exists():
            try:
                data = json.loads(status_file.read_text(encoding="utf-8"))
                for item in data.get("checks", []):
                    if item.get("status") in ("compliant", "partial"):
                        satisfied_checks.add(item["check_id"])
            except (json.JSONDecodeError, KeyError):
                pass

        for check in checks:
            check_id = check["id"]
            if check_id not in satisfied_checks:
                findings.append(ComplianceFinding(
                    framework=check.get("framework", ""),
                    check_id=check_id,
                    title=check.get("check", ""),
                    status=ComplianceStatus.NON_COMPLIANT,
                    severity=Severity(check.get("severity", "medium")),
                    detail=f"No evidence found for: {check.get('check', check_id)}",
                    corrective_action=check.get("remediation", ""),
                ))

        return findings

    def _find_evidence(self, directory: Path) -> set[str]:
        """Walk the directory and find check IDs satisfied by existing files."""
        satisfied: set[str] = set()

        try:
            items = list(directory.iterdir())
        except PermissionError:
            return satisfied

        for item in items:
            name_lower = item.stem.lower().replace("-", "_").replace(" ", "_")

            for key, check_ids in _EVIDENCE_MAP.items():
                if key in name_lower:
                    satisfied.update(check_ids)

            # Recurse one level into subdirectories
            if item.is_dir():
                for sub_item in item.iterdir():
                    sub_name = sub_item.stem.lower().replace("-", "_").replace(" ", "_")
                    for key, check_ids in _EVIDENCE_MAP.items():
                        if key in sub_name:
                            satisfied.update(check_ids)

        return satisfied
