# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""CRUD operations for Social Worker cases, resources, notes, and crisis log.

Data stored in ~/.familiar/data/cases.json with structure:
{
    "cases": [...],
    "resources": [...],
    "notes": [...],
    "crisis_log": [...]
}
"""

import json
import logging
import uuid
from datetime import datetime
from pathlib import Path

logger = logging.getLogger(__name__)

# HUD HMIS Universal Data Element defaults (P7 upgrade)
_HMIS_DEFAULTS = {
    # Demographics
    "dob": "",
    "race": [],
    "ethnicity": "",
    "gender": "",
    "veteran_status": "",
    "disability_status": "",
    "disability_types": [],
    # Housing / Living
    "prior_living": "",
    "destination": "",
    "entry_date": "",
    "exit_date": "",
    "move_in_date": "",
    # Income & Benefits
    "income_sources": [],
    "total_monthly_income": 0,
    "non_cash_benefits": [],
    "health_insurance": [],
    # Domestic Violence
    "dv_survivor": "",
    "dv_when": "",
    "dv_currently_fleeing": "",
    # Clinical assessments (SAMHSA standard)
    "assessments": [],
    # Safety plan (Stanley-Brown)
    "safety_plan": {},
    # Mandatory reporting
    "mandatory_report_flags": [],
}


def _backfill_case(case: dict) -> dict:
    """Backfill HMIS/clinical fields onto legacy case records."""
    for key, default in _HMIS_DEFAULTS.items():
        if key not in case:
            case[key] = (
                default
                if not isinstance(default, (list, dict))
                else (list(default) if isinstance(default, list) else dict(default))
            )
    return case


def _get_data_dir() -> Path:
    try:
        from familiar.core import paths

        return paths.DATA_DIR
    except ImportError:
        return Path.home() / ".familiar" / "data"


def _get_data_file() -> Path:
    return _get_data_dir() / "cases.json"


_DEFAULT_DATA = {"cases": [], "resources": [], "notes": [], "crisis_log": []}


def _load_data() -> dict:
    f = _get_data_file()
    if f.exists():
        try:
            with open(f, encoding="utf-8") as fh:
                return json.load(fh)
        except (json.JSONDecodeError, IOError, OSError) as e:
            logger.warning("Failed to load cases data: %s", e)
    return json.loads(json.dumps(_DEFAULT_DATA))


def _save_data(data: dict) -> None:
    f = _get_data_file()
    f.parent.mkdir(parents=True, exist_ok=True)
    with open(f, "w", encoding="utf-8") as fh:
        json.dump(data, fh, indent=2)


# ── Cases CRUD ──


def get_all_cases() -> list:
    cases = _load_data().get("cases", [])
    for c in cases:
        _backfill_case(c)
    return cases


def add_case(info: dict) -> dict:
    data = _load_data()
    case = {
        "id": str(uuid.uuid4())[:8],
        "name": info.get("name", "Unnamed Case"),
        "category": info.get("category", "general"),
        "status": info.get("status", "intake"),
        "priority": info.get("priority", "normal"),
        "assigned_to": info.get("assigned_to", ""),
        "phone": info.get("phone", ""),
        "email": info.get("email", ""),
        "address": info.get("address", ""),
        "notes": info.get("notes", ""),
        "created_at": datetime.now().isoformat(),
        "updated_at": datetime.now().isoformat(),
        "follow_up_date": info.get("follow_up_date", ""),
        "interactions": [
            {
                "date": datetime.now().isoformat(),
                "type": "intake",
                "description": "Case opened",
            }
        ],
    }
    # HMIS Universal Data Elements + clinical fields
    for key, default in _HMIS_DEFAULTS.items():
        val = info.get(key)
        case[key] = (
            val
            if val is not None
            else (
                default
                if not isinstance(default, (list, dict))
                else (list(default) if isinstance(default, list) else dict(default))
            )
        )
    data.setdefault("cases", []).append(case)
    _save_data(data)
    return case


def update_case(info: dict) -> dict:
    data = _load_data()
    case_id = info.get("id", "")
    for case in data.get("cases", []):
        if case["id"] == case_id:
            for k, v in info.items():
                if k != "id" and v is not None:
                    case[k] = v
            case["updated_at"] = datetime.now().isoformat()
            _save_data(data)
            return case
    return {"error": f"Case {case_id} not found"}


def delete_case(case_id: str) -> dict:
    data = _load_data()
    cases = data.get("cases", [])
    original_len = len(cases)
    data["cases"] = [c for c in cases if c["id"] != case_id]
    if len(data["cases"]) == original_len:
        return {"error": f"Case {case_id} not found"}
    _save_data(data)
    return {"success": True}


def add_case_interaction(info: dict) -> dict:
    data = _load_data()
    case_id = info.get("case_id", "")
    for case in data.get("cases", []):
        if case["id"] == case_id:
            ix = {
                "date": info.get("date", datetime.now().isoformat()),
                "type": info.get("type", "note"),
                "description": info.get("description", ""),
            }
            case.setdefault("interactions", []).append(ix)
            case["updated_at"] = datetime.now().isoformat()
            _save_data(data)
            return case
    return {"error": f"Case {case_id} not found"}


# ── Resources CRUD ──


def get_all_resources() -> list:
    return _load_data().get("resources", [])


def add_resource(info: dict) -> dict:
    data = _load_data()
    resource = {
        "id": str(uuid.uuid4())[:8],
        "name": info.get("name", ""),
        "category": info.get("category", "general"),
        "phone": info.get("phone", ""),
        "address": info.get("address", ""),
        "website": info.get("website", ""),
        "hours": info.get("hours", ""),
        "notes": info.get("notes", ""),
        "created_at": datetime.now().isoformat(),
    }
    data.setdefault("resources", []).append(resource)
    _save_data(data)
    return resource


def update_resource(info: dict) -> dict:
    data = _load_data()
    res_id = info.get("id", "")
    for res in data.get("resources", []):
        if res["id"] == res_id:
            for k, v in info.items():
                if k != "id" and v is not None:
                    res[k] = v
            _save_data(data)
            return res
    return {"error": f"Resource {res_id} not found"}


def delete_resource(res_id: str) -> dict:
    data = _load_data()
    resources = data.get("resources", [])
    original_len = len(resources)
    data["resources"] = [r for r in resources if r["id"] != res_id]
    if len(data["resources"]) == original_len:
        return {"error": f"Resource {res_id} not found"}
    _save_data(data)
    return {"success": True}


# ── Case Notes CRUD ──


def get_all_case_notes() -> list:
    return _load_data().get("notes", [])


def add_case_note(info: dict) -> dict:
    data = _load_data()
    note = {
        "id": str(uuid.uuid4())[:8],
        "case_id": info.get("case_id", ""),
        "case_name": info.get("case_name", ""),
        "category": info.get("category", "progress"),
        "content": info.get("content", ""),
        "date": info.get("date", datetime.now().isoformat()[:10]),
        "created_at": datetime.now().isoformat(),
    }
    data.setdefault("notes", []).append(note)
    _save_data(data)
    return note


def delete_case_note(note_id: str) -> dict:
    data = _load_data()
    notes = data.get("notes", [])
    original_len = len(notes)
    data["notes"] = [n for n in notes if n["id"] != note_id]
    if len(data["notes"]) == original_len:
        return {"error": f"Note {note_id} not found"}
    _save_data(data)
    return {"success": True}


# ── Crisis Log CRUD ──


def get_all_crisis_events() -> list:
    return _load_data().get("crisis_log", [])


def add_crisis_event(info: dict) -> dict:
    data = _load_data()
    event = {
        "id": str(uuid.uuid4())[:8],
        "case_id": info.get("case_id", ""),
        "case_name": info.get("case_name", ""),
        "severity": info.get("severity", "moderate"),
        "summary": info.get("summary", ""),
        "outcome": info.get("outcome", ""),
        "date": info.get("date", datetime.now().isoformat()[:10]),
        "created_at": datetime.now().isoformat(),
    }
    data.setdefault("crisis_log", []).append(event)
    _save_data(data)
    return event


def delete_crisis_event(event_id: str) -> dict:
    data = _load_data()
    events = data.get("crisis_log", [])
    original_len = len(events)
    data["crisis_log"] = [e for e in events if e["id"] != event_id]
    if len(data["crisis_log"]) == original_len:
        return {"error": f"Crisis event {event_id} not found"}
    _save_data(data)
    return {"success": True}


# ── Clinical Assessments (SAMHSA) ──


def add_assessment(case_id: str, assessment: dict) -> dict:
    """Add a clinical assessment (PHQ-9, GAD-7, C-SSRS, AUDIT, DAST-10, ACE) to a case."""
    data = _load_data()
    for case in data.get("cases", []):
        if case["id"] == case_id:
            _backfill_case(case)
            entry = {
                "id": str(uuid.uuid4())[:8],
                "tool": assessment.get("tool", ""),
                "date": assessment.get("date", datetime.now().isoformat()[:10]),
                "score": assessment.get("score", 0),
                "severity": assessment.get("severity", ""),
                "risk_level": assessment.get("risk_level", ""),
                "ideation": assessment.get("ideation", False),
                "plan": assessment.get("plan", False),
                "intent": assessment.get("intent", False),
                "notes": assessment.get("notes", ""),
            }
            case["assessments"].append(entry)
            case["updated_at"] = datetime.now().isoformat()
            _save_data(data)
            return entry
    return {"error": f"Case {case_id} not found"}


def get_assessments(case_id: str) -> list:
    """Get all assessments for a case."""
    for case in get_all_cases():
        if case["id"] == case_id:
            return case.get("assessments", [])
    return []


# ── Safety Plan (Stanley-Brown) ──


def save_safety_plan(case_id: str, plan: dict) -> dict:
    """Save or update a Stanley-Brown safety plan for a case."""
    data = _load_data()
    for case in data.get("cases", []):
        if case["id"] == case_id:
            _backfill_case(case)
            case["safety_plan"] = {
                "warning_signs": plan.get("warning_signs", []),
                "coping_strategies": plan.get("coping_strategies", []),
                "social_contacts": plan.get("social_contacts", []),
                "professional_contacts": plan.get("professional_contacts", []),
                "environment_safety": plan.get("environment_safety", ""),
                "reasons_for_living": plan.get("reasons_for_living", []),
                "created_date": plan.get(
                    "created_date",
                    case.get("safety_plan", {}).get(
                        "created_date", datetime.now().isoformat()[:10]
                    ),
                ),
                "last_reviewed": datetime.now().isoformat()[:10],
            }
            case["updated_at"] = datetime.now().isoformat()
            _save_data(data)
            return case["safety_plan"]
    return {"error": f"Case {case_id} not found"}


# ── Mandatory Reporting ──


def add_mandatory_report(case_id: str, report: dict) -> dict:
    """Log a mandatory report (child abuse, elder abuse, DV, self-harm)."""
    data = _load_data()
    for case in data.get("cases", []):
        if case["id"] == case_id:
            _backfill_case(case)
            entry = {
                "id": str(uuid.uuid4())[:8],
                "type": report.get("type", ""),
                "date": report.get("date", datetime.now().isoformat()[:10]),
                "reported_to": report.get("reported_to", ""),
                "report_id": report.get("report_id", ""),
                "notes": report.get("notes", ""),
            }
            case["mandatory_report_flags"].append(entry)
            case["updated_at"] = datetime.now().isoformat()
            _save_data(data)
            return entry
    return {"error": f"Case {case_id} not found"}
