import json
import logging
from typing import Any, Optional

logger = logging.getLogger(__name__)

BASIC_INFO_FIELDS = {
    "case_number", "title", "cause", "source", "filing_date", "status",
    "description", "enforcement_region",
}

PARTY_INFO_FIELDS = {
    "name": "party_name",
    "type": "party_type",
    "credit_code": "credit_code",
    "legal_representative": "legal_representative",
    "id_type": "party_id_type",
    "id_number": "party_id_number",
    "phone": "phone",
    "address": "address",
}

OFFICER_INFO_FIELDS = {
    "main_officer", "assistant_officer",
}

ILLEGAL_FACT_FIELDS = {
    "summary": "illegal_fact_summary",
    "involved_amount": "involved_amount",
    "legal_basis": "legal_basis",
}

POOL_RELATED_DB_FIELDS = (
    BASIC_INFO_FIELDS
    | set(PARTY_INFO_FIELDS.values())
    | OFFICER_INFO_FIELDS
    | set(ILLEGAL_FACT_FIELDS.values())
)


class InfoPoolService:

    async def initialize(self, case_id: str, case_data: dict, db) -> dict:
        conn, cur = db
        pool = self.to_dict(case_data)
        pool_json = json.dumps(pool, ensure_ascii=False, default=str)
        await cur.execute(
            "UPDATE cases SET info_pool = %s WHERE id = %s",
            (pool_json, case_id),
        )
        return pool

    async def get(self, case_id: str, db) -> Optional[dict]:
        conn, cur = db
        await cur.execute(
            "SELECT info_pool, case_number, title, cause, source, "
            "filing_date, status, party_name, party_type, credit_code, "
            "legal_representative, party_id_type, party_id_number, phone, "
            "address, main_officer, assistant_officer, illegal_fact_summary, "
            "involved_amount FROM cases WHERE id = %s",
            (case_id,),
        )
        row = await cur.fetchone()
        if not row:
            return None
        if dict(row).get("info_pool"):
            if isinstance(row["info_pool"], str):
                try:
                    return json.loads(row["info_pool"])
                except (json.JSONDecodeError, TypeError):
                    pass
            elif isinstance(row["info_pool"], dict):
                return row["info_pool"]
        return self.to_dict(dict(row))

    async def sync_update(self, case_id: str, updated_fields: dict, db) -> bool:
        pool_related_changed = bool(
            POOL_RELATED_DB_FIELDS & set(updated_fields.keys())
        )
        if not pool_related_changed:
            return False
        conn, cur = db
        await cur.execute(
            "SELECT case_number, title, cause, source, filing_date, status, "
            "party_name, party_type, credit_code, legal_representative, "
            "party_id_type, party_id_number, phone, address, main_officer, "
            "assistant_officer, illegal_fact_summary, involved_amount "
            "FROM cases WHERE id = %s",
            (case_id,),
        )
        row = await cur.fetchone()
        if not row:
            return False
        pool = self.to_dict(dict(row))
        pool_json = json.dumps(pool, ensure_ascii=False, default=str)
        await cur.execute(
            "UPDATE cases SET info_pool = %s WHERE id = %s",
            (pool_json, case_id),
        )
        return True

    def to_dict(self, case_data: dict) -> dict:
        basic_info: dict[str, Any] = {}
        for field in BASIC_INFO_FIELDS:
            basic_info[field] = case_data.get(field)

        party_info: dict[str, Any] = {}
        for pool_key, db_key in PARTY_INFO_FIELDS.items():
            party_info[pool_key] = case_data.get(db_key)

        officer_info: dict[str, Any] = {}
        for field in OFFICER_INFO_FIELDS:
            value = case_data.get(field)
            if isinstance(value, str):
                try:
                    value = json.loads(value)
                except (json.JSONDecodeError, TypeError):
                    value = None
            officer_info[field] = value

        illegal_fact: dict[str, Any] = {}
        for pool_key, db_key in ILLEGAL_FACT_FIELDS.items():
            illegal_fact[pool_key] = case_data.get(db_key)

        return {
            "basic_info": basic_info,
            "party_info": party_info,
            "officer_info": officer_info,
            "illegal_fact": illegal_fact,
        }


info_pool_service = InfoPoolService()
