"""Provider, payer, and clearhouse configuration reads and upserts.

The ``providers`` and ``payers`` modules in ``cyclone`` provide the
ORM-row DTOs; this module is the read/upsert surface over them.
``ensure_clearhouse_seeded`` is called at startup to insert the
default Clearhouse row if missing.
"""

import json
from datetime import datetime, timezone

from cyclone import db
from cyclone.providers import Clearhouse, Payer, Provider

from . import utcnow


# ------------------------------------------------------------------
# SP9: providers / payers / payer_configs / clearhouse
# ------------------------------------------------------------------

def list_providers(*, is_active: bool | None = True) -> list[Provider]:
    """List providers. ``is_active=None`` returns all."""
    from cyclone.db import Provider as ProviderORM
    from cyclone.providers import Provider
    with db.SessionLocal()() as s:
        q = s.query(ProviderORM)
        if is_active is not None:
            q = q.filter(ProviderORM.is_active == (1 if is_active else 0))
        rows = q.order_by(ProviderORM.label).all()
        return [Provider.model_validate(_provider_orm_to_dict(r)) for r in rows]

def get_provider(npi: str) -> Provider | None:
    from cyclone.db import Provider as ProviderORM
    from cyclone.providers import Provider
    with db.SessionLocal()() as s:
        row = s.get(ProviderORM, npi)
        return Provider.model_validate(_provider_orm_to_dict(row)) if row else None

def upsert_provider(provider: Provider) -> Provider:
    from cyclone.db import Provider as ProviderORM
    with db.SessionLocal()() as s:
        row = s.get(ProviderORM, provider.npi)
        now = utcnow().isoformat()
        if row is None:
            row = ProviderORM(
                npi=provider.npi, label=provider.label,
                legal_name=provider.legal_name, tax_id=provider.tax_id,
                taxonomy_code=provider.taxonomy_code,
                address_line1=provider.address_line1,
                address_line2=provider.address_line2,
                city=provider.city, state=provider.state, zip=provider.zip,
                is_active=1 if provider.is_active else 0,
                created_at=provider.created_at.isoformat(),
                updated_at=now,
            )
            s.add(row)
        else:
            row.label = provider.label
            row.legal_name = provider.legal_name
            row.tax_id = provider.tax_id
            row.taxonomy_code = provider.taxonomy_code
            row.address_line1 = provider.address_line1
            row.address_line2 = provider.address_line2
            row.city = provider.city
            row.state = provider.state
            row.zip = provider.zip
            row.is_active = 1 if provider.is_active else 0
            row.updated_at = now
        s.commit()
    return get_provider(provider.npi)  # type: ignore[return-value]

def list_payers(*, is_active: bool | None = True) -> list[Payer]:
    from cyclone.db import Payer as PayerORM
    from cyclone.providers import Payer
    with db.SessionLocal()() as s:
        q = s.query(PayerORM)
        if is_active is not None:
            q = q.filter(PayerORM.is_active == (1 if is_active else 0))
        rows = q.order_by(PayerORM.payer_id).all()
        return [Payer.model_validate(_payer_orm_to_dict(r)) for r in rows]

def get_payer_config(payer_id: str, transaction_type: str) -> dict | None:
    from cyclone.db import PayerConfigORM
    with db.SessionLocal()() as s:
        row = s.get(PayerConfigORM, (payer_id, transaction_type))
        return dict(row.config_json) if row else None

def get_clearhouse() -> Clearhouse | None:
    from cyclone.db import ClearhouseORM
    from cyclone.providers import Clearhouse
    with db.SessionLocal()() as s:
        row = s.get(ClearhouseORM, 1)
        if row is None:
            return None
        return Clearhouse.model_validate({
            "id": 1,
            "name": row.name,
            "tpid": row.tpid,
            "submitter_name": row.submitter_name,
            "submitter_id_qual": row.submitter_id_qual,
            "submitter_contact_name": row.submitter_contact_name,
            "submitter_contact_email": row.submitter_contact_email,
            "filename_block": dict(row.filename_block_json),
            "sftp_block": dict(row.sftp_block_json),
            "updated_at": row.updated_at,
        })

def update_clearhouse(block: Clearhouse) -> Clearhouse:
    """Replace the singleton clearhouse row. SP25.

    Used by ``PATCH /api/clearhouse`` to flip ``sftp_block.stub``
    and adjust host/port/paths without touching SQLite directly.
    Raises ``LookupError`` if the singleton row is missing — the
    caller is expected to run the lifespan seed first.
    """
    from cyclone.db import ClearhouseORM
    with db.SessionLocal()() as s:
        row = s.get(ClearhouseORM, 1)
        if row is None:
            raise LookupError(
                "clearhouse singleton row missing; run the lifespan "
                "seed (ensure_clearhouse_seeded) before PATCH /api/clearhouse"
            )
        row.name = block.name
        row.tpid = block.tpid
        row.submitter_name = block.submitter_name
        row.submitter_id_qual = block.submitter_id_qual
        row.submitter_contact_name = block.submitter_contact_name
        row.submitter_contact_email = block.submitter_contact_email
        row.filename_block_json = json.loads(
            json.dumps(block.filename_block.model_dump())
        )
        row.sftp_block_json = json.loads(
            json.dumps(block.sftp_block.model_dump())
        )
        row.updated_at = datetime.now(timezone.utc).isoformat()
        s.commit()
        return Clearhouse.model_validate({
            "id": 1,
            "name": row.name,
            "tpid": row.tpid,
            "submitter_name": row.submitter_name,
            "submitter_id_qual": row.submitter_id_qual,
            "submitter_contact_name": row.submitter_contact_name,
            "submitter_contact_email": row.submitter_contact_email,
            "filename_block": dict(row.filename_block_json),
            "sftp_block": dict(row.sftp_block_json),
            "updated_at": row.updated_at,
        })

def ensure_clearhouse_seeded() -> None:
    """Insert the default clearhouse singleton + 3 providers + CO_TXIX payer
    if they don't exist. Idempotent. Called from the API lifespan."""
    from cyclone.db import ClearhouseORM, Payer as PayerORM, PayerConfigORM, Provider as ProviderORM
    from cyclone.providers import Clearhouse
    with db.SessionLocal()() as s:
        if s.get(ClearhouseORM, 1) is None:
            ch = Clearhouse(
                id=1,
                name="dzinesco",
                tpid="11525703",
                submitter_name="Dzinesco",
                submitter_id_qual="46",
                submitter_contact_name="Tyler Martinez",
                submitter_contact_email="tyler@dzinesco.com",
                filename_block={
                    "tz": "America/Denver",
                    "outbound_template": "tp{tpid}-{tx}-{ts_mt}-1of1.{ext}",
                    "inbound_template": "TP{tpid}-{orig_tx}_M{tracking}-{ts}-1of1_{file_type}.x12",
                },
                sftp_block={
                    "host": "mft.gainwelltechnologies.com",
                    "port": 22,
                    "username": "colorado-fts\\coxix_prod_11525703",
                    "paths": {
                        "outbound": "/CO XIX/PROD/coxix_prod_11525703/ToHPE",
                        "inbound": "/CO XIX/PROD/coxix_prod_11525703/FromHPE",
                    },
                    "stub": True,
                    "staging_dir": "./var/sftp/staging",
                    "poll_seconds": 300,
                    "auth": {"method": "keychain", "secret_ref": "sftp.gainwell.password"},
                },
                updated_at=utcnow(),
            )
            s.add(ClearhouseORM(
                id=1,
                name=ch.name,
                tpid=ch.tpid,
                submitter_name=ch.submitter_name,
                submitter_id_qual=ch.submitter_id_qual,
                submitter_contact_name=ch.submitter_contact_name,
                submitter_contact_email=ch.submitter_contact_email,
                filename_block_json=ch.filename_block.model_dump(),
                sftp_block_json=ch.sftp_block.model_dump(),
                updated_at=ch.updated_at.isoformat(),
            ))

        # Seed 3 providers (idempotent)
        from cyclone.providers import Provider
        now = utcnow().isoformat()
        for npi, label in [
            ("1881068062", "Montrose"),
            ("1851446637", "Delta"),
            ("1467507269", "Salida"),
        ]:
            if s.get(ProviderORM, npi) is None:
                s.add(ProviderORM(
                    npi=npi,
                    label=label,
                    legal_name="TOC, Inc.",
                    tax_id="721587149",
                    taxonomy_code="251E00000X",
                    address_line1="1100 East Main St",
                    address_line2="Suite A",
                    city="Montrose",
                    state="CO",
                    zip="814014063",
                    is_active=1,
                    created_at=now,
                    updated_at=now,
                ))

        # Seed CO_TXIX payer (idempotent)
        if s.get(PayerORM, "CO_TXIX") is None:
            s.add(PayerORM(
                payer_id="CO_TXIX",
                name="Colorado Medical Assistance Program",
                receiver_name="COLORADO MEDICAL ASSISTANCE PROGRAM",
                receiver_id="COMEDASSISTPROG",
                is_active=1,
                created_at=now,
                updated_at=now,
            ))
            # 837P config block
            s.add(PayerConfigORM(
                payer_id="CO_TXIX",
                transaction_type="837P",
                config_json={
                    "submitter_name": "Dzinesco",
                    "submitter_contact_name": "Tyler Martinez",
                    "submitter_contact_email": "tyler@dzinesco.com",
                    "receiver_name": "COLORADO MEDICAL ASSISTANCE PROGRAM",
                    "receiver_id_qualifier": "46",
                    "receiver_id": "COMEDASSISTPROG",
                    "bht06_allowed": ["CH", "RP"],
                    "bht06_default": "CH",
                    "sbr09_default": "MC",
                    "sbr09_allowed": ["MC", "16", "MA", "MB", "ZZ"],
                    "payer_id_qualifier": "PI",
                    "payer_id": "CO_TXIX",
                    "pwk_supported": False,
                    "cas_2320_group_allowed": False,
                    "claim_type_codes": {"11": "Office", "12": "Home", "99": "Other"},
                },
                updated_at=now,
            ))
            # 835 config block
            s.add(PayerConfigORM(
                payer_id="CO_TXIX",
                transaction_type="835",
                config_json={
                    "expected_payer_tax_ids": [
                        "81-1725341", "811725341", "84-0644739",
                        "840644739", "1811725341",
                    ],
                    "expected_payer_health_plan_id": "7912900843",
                    "payer_name_pattern": "^CO_(TXIX|BHA)$",
                },
                updated_at=now,
            ))

        s.commit()




def _provider_orm_to_dict(row) -> dict:
    return {
        "npi": row.npi,
        "label": row.label,
        "legal_name": row.legal_name,
        "tax_id": row.tax_id,
        "taxonomy_code": row.taxonomy_code,
        "address_line1": row.address_line1,
        "address_line2": row.address_line2,
        "city": row.city,
        "state": row.state,
        "zip": row.zip,
        "is_active": bool(row.is_active),
        "created_at": row.created_at,
        "updated_at": row.updated_at,
    }


def _payer_orm_to_dict(row) -> dict:
    return {
        "payer_id": row.payer_id,
        "name": row.name,
        "receiver_name": row.receiver_name,
        "receiver_id": row.receiver_id,
        "is_active": bool(row.is_active),
        "created_at": row.created_at,
        "updated_at": row.updated_at,
    }

