import logging
from datetime import datetime
from typing import Any, Optional

from app.core.database import execute_query, execute_query_single

logger = logging.getLogger(__name__)


class TelefoniService:
    @staticmethod
    def find_user_by_extension(extension: Optional[str]) -> list[int]:
        """Find all users with the given extension - returns list of user_ids."""
        if not extension:
            return []
        rows = execute_query(
            "SELECT user_id FROM users WHERE telefoni_aktiv = TRUE AND telefoni_extension = %s ORDER BY user_id",
            (extension,),
        )
        return [int(row["user_id"]) for row in rows if row.get("user_id") is not None]

    @staticmethod
    def find_contact_by_phone(number: Optional[str]) -> Optional[dict]:
        """Two-step lookup: full normalised number first, 8-digit suffix as fallback."""
        from app.modules.telefoni.backend.utils import phone_digits_full, phone_suffix_8

        full = phone_digits_full(number)
        suffix = phone_suffix_8(number)

        if not full and not suffix:
            return None

        _contact_cte = """
            SELECT
                c.id,
                c.first_name,
                c.last_name,
                (
                    SELECT cu.id
                    FROM contact_companies cc
                    JOIN customers cu ON cu.id = cc.customer_id
                    WHERE cc.contact_id = c.id
                    ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
                    LIMIT 1
                ) AS company_id,
                (
                    SELECT cu.name
                    FROM contact_companies cc
                    JOIN customers cu ON cu.id = cc.customer_id
                    WHERE cc.contact_id = c.id
                    ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
                    LIMIT 1
                ) AS company,
                (
                    SELECT COUNT(*)
                    FROM sag_kontakter sk
                    JOIN sag_sager s ON s.id = sk.sag_id
                    WHERE sk.contact_id = c.id
                      AND sk.deleted_at IS NULL
                      AND s.deleted_at IS NULL
                      AND LOWER(COALESCE(s.status, '')) <> 'lukket'
                ) AS open_case_count,
                (
                    SELECT MAX(t.started_at)
                    FROM telefoni_opkald t
                    WHERE t.kontakt_id = c.id
                ) AS last_call_at
            FROM contacts c
        """

        row = None

        # Step 1: exact full-digit match (strips country code first)
        if full:
            query_full = _contact_cte + """
                WHERE regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g') LIKE %s
                   OR regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g') LIKE %s
                ORDER BY open_case_count DESC, last_call_at DESC NULLS LAST, c.id ASC
                LIMIT 1
            """
            # Match ending with full digits (covers both with and without country code stored)
            pattern = f"%{full}"
            row = execute_query_single(query_full, (pattern, pattern))
            if row:
                logger.debug("📞 Phone lookup: full-digit match for %s → contact %s", number, row["id"])

        # Step 2: 8-digit suffix fallback
        if not row and suffix:
            query_suffix = _contact_cte + """
                WHERE RIGHT(regexp_replace(COALESCE(c.phone, ''), '\\D', '', 'g'), 8) = %s
                   OR RIGHT(regexp_replace(COALESCE(c.mobile, ''), '\\D', '', 'g'), 8) = %s
                ORDER BY open_case_count DESC, last_call_at DESC NULLS LAST, c.id ASC
                LIMIT 1
            """
            row = execute_query_single(query_suffix, (suffix, suffix))
            if row:
                logger.debug("📞 Phone lookup: suffix-8 fallback for %s → contact %s", number, row["id"])

        if not row:
            return None
        return {
            "id": row["id"],
            "name": f"{(row.get('first_name') or '').strip()} {(row.get('last_name') or '').strip()}".strip(),
            "company_id": row.get("company_id"),
            "company": row.get("company"),
        }

    @staticmethod
    def find_contact_by_phone_suffix(suffix8: Optional[str]) -> Optional[dict]:
        """Deprecated: use find_contact_by_phone(). Kept for backward compatibility."""
        return TelefoniService.find_contact_by_phone(suffix8)

    @staticmethod
    def upsert_call(
        *,
        callid: str,
        user_id: Optional[int],
        direction: str,
        ekstern_nummer: Optional[str],
        intern_extension: Optional[str],
        kontakt_id: Optional[int],
        raw_payload: Any,
        started_at: datetime,
    ) -> dict:
        query = """
            INSERT INTO telefoni_opkald
                (callid, bruger_id, direction, ekstern_nummer, intern_extension, kontakt_id, started_at, raw_payload)
            VALUES
                (%s, %s, %s, %s, %s, %s, %s, %s::jsonb)
            ON CONFLICT (callid)
            DO UPDATE SET
                raw_payload = EXCLUDED.raw_payload,
                direction = EXCLUDED.direction,
                intern_extension = COALESCE(telefoni_opkald.intern_extension, EXCLUDED.intern_extension),
                ekstern_nummer = COALESCE(telefoni_opkald.ekstern_nummer, EXCLUDED.ekstern_nummer),
                bruger_id = COALESCE(telefoni_opkald.bruger_id, EXCLUDED.bruger_id),
                kontakt_id = COALESCE(telefoni_opkald.kontakt_id, EXCLUDED.kontakt_id),
                started_at = LEAST(telefoni_opkald.started_at, EXCLUDED.started_at)
            RETURNING *
        """
        rows = execute_query(
            query,
            (
                callid,
                user_id,
                direction,
                ekstern_nummer,
                intern_extension,
                kontakt_id,
                started_at,
                raw_payload,
            ),
        )
        return rows[0] if rows else {}

    @staticmethod
    def terminate_call(callid: str, duration_sec: Optional[int]) -> bool:
        if not callid:
            return False
        rows = execute_query(
            """
            UPDATE telefoni_opkald
            SET ended_at = NOW(),
                duration_sec = COALESCE(
                    %s,
                    CASE
                        WHEN started_at IS NOT NULL THEN GREATEST(EXTRACT(EPOCH FROM (NOW() - started_at))::int, 0)
                        ELSE NULL
                    END
                )
            WHERE callid = %s
            RETURNING id
            """,
            (duration_sec, callid),
        )
        return bool(rows)

    @staticmethod
    def get_contact_details(contact_id: int, company_id: Optional[int] = None) -> dict:
        """Get extended contact details for telefoni popups and call notifications."""
        if not contact_id:
            return {
                "recent_cases": [],
                "contact_cases": [],
                "company_cases": [],
                "related_contacts": [],
                "last_call": None,
            }

        contact_row = execute_query_single(
            """
            SELECT
                c.id,
                c.first_name,
                c.last_name,
                c.email,
                c.phone,
                c.mobile,
                c.title,
                c.department,
                c.is_active,
                c.user_company,
                (
                    SELECT cu.id
                    FROM contact_companies cc
                    JOIN customers cu ON cu.id = cc.customer_id
                    WHERE cc.contact_id = c.id
                    ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
                    LIMIT 1
                ) AS company_id,
                (
                    SELECT cu.name
                    FROM contact_companies cc
                    JOIN customers cu ON cu.id = cc.customer_id
                    WHERE cc.contact_id = c.id
                    ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
                    LIMIT 1
                ) AS company
            FROM contacts c
            WHERE c.id = %s
            """,
            (contact_id,),
        )

        effective_company_id = company_id or (contact_row.get("company_id") if contact_row else None)

        open_cases_query = """
            SELECT
                s.id,
                s.titel,
                s.created_at
            FROM sag_sager s
            INNER JOIN sag_kontakter sk ON s.id = sk.sag_id
            WHERE sk.contact_id = %s
              AND s.status = 'åben'
              AND s.deleted_at IS NULL
              AND sk.deleted_at IS NULL
            ORDER BY s.created_at DESC
            LIMIT 3
        """
        recent_open_cases = execute_query(open_cases_query, (contact_id,)) or []

        contact_cases_query = """
            SELECT
                s.id,
                s.titel,
                s.status,
                s.customer_id,
                cu.name AS customer_name,
                s.created_at,
                s.updated_at
            FROM sag_sager s
            INNER JOIN sag_kontakter sk ON s.id = sk.sag_id
            LEFT JOIN customers cu ON cu.id = s.customer_id
            WHERE sk.contact_id = %s
              AND s.deleted_at IS NULL
              AND sk.deleted_at IS NULL
            ORDER BY COALESCE(s.updated_at, s.created_at) DESC
            LIMIT 5
        """
        contact_cases = execute_query(contact_cases_query, (contact_id,)) or []

        company_cases = []
        related_contacts = []
        if effective_company_id:
            company_cases_query = """
                SELECT
                    s.id,
                    s.titel,
                    s.status,
                    s.customer_id,
                    cu.name AS customer_name,
                    s.created_at,
                    s.updated_at
                FROM sag_sager s
                LEFT JOIN customers cu ON cu.id = s.customer_id
                WHERE s.customer_id = %s
                  AND s.deleted_at IS NULL
                ORDER BY COALESCE(s.updated_at, s.created_at) DESC
                LIMIT 5
            """
            company_cases = execute_query(company_cases_query, (effective_company_id,)) or []

            related_contacts_query = """
                SELECT
                    c.id,
                    c.first_name,
                    c.last_name,
                    c.email,
                    c.phone,
                    c.mobile,
                    c.title,
                    c.department,
                    c.is_active,
                    c.created_at,
                    c.updated_at,
                    ARRAY_AGG(DISTINCT cu.name ORDER BY cu.name) FILTER (WHERE cu.name IS NOT NULL) AS company_names
                FROM contacts c
                INNER JOIN contact_companies cc ON c.id = cc.contact_id
                INNER JOIN customers cu ON cc.customer_id = cu.id
                WHERE cc.customer_id = %s
                  AND c.id <> %s
                  AND c.is_active = TRUE
                GROUP BY c.id, c.first_name, c.last_name, c.email, c.phone, c.mobile, c.title, c.department, c.is_active, c.created_at, c.updated_at
                ORDER BY c.last_name, c.first_name
                LIMIT 8
            """
            related_contacts = execute_query(related_contacts_query, (effective_company_id, contact_id)) or []

        last_call_query = """
            SELECT
                t.started_at,
                t.bruger_id,
                t.duration_sec,
                u.full_name,
                u.username
            FROM telefoni_opkald t
            LEFT JOIN users u ON t.bruger_id = u.user_id
            WHERE t.kontakt_id = %s
              AND t.ended_at IS NOT NULL
            ORDER BY t.started_at DESC
            LIMIT 1
        """
        last_call_row = execute_query_single(last_call_query, (contact_id,))

        last_call_data = None
        if last_call_row:
            last_call_data = {
                "started_at": last_call_row.get("started_at"),
                "bruger_navn": last_call_row.get("full_name") or last_call_row.get("username"),
                "duration_sec": last_call_row.get("duration_sec"),
            }

        return {
            "recent_cases": [
                {
                    "id": case["id"],
                    "titel": case["titel"],
                    "created_at": case["created_at"],
                }
                for case in recent_open_cases
            ],
            "contact_cases": [
                {
                    "id": case["id"],
                    "titel": case["titel"],
                    "status": case.get("status"),
                    "customer_id": case.get("customer_id"),
                    "customer_name": case.get("customer_name"),
                    "created_at": case.get("created_at"),
                    "updated_at": case.get("updated_at"),
                }
                for case in contact_cases
            ],
            "company_cases": [
                {
                    "id": case["id"],
                    "titel": case["titel"],
                    "status": case.get("status"),
                    "customer_id": case.get("customer_id"),
                    "customer_name": case.get("customer_name"),
                    "created_at": case.get("created_at"),
                    "updated_at": case.get("updated_at"),
                }
                for case in company_cases
            ],
            "related_contacts": [
                {
                    "id": contact["id"],
                    "first_name": contact.get("first_name"),
                    "last_name": contact.get("last_name"),
                    "email": contact.get("email"),
                    "phone": contact.get("phone"),
                    "mobile": contact.get("mobile"),
                    "title": contact.get("title"),
                    "department": contact.get("department"),
                    "is_active": contact.get("is_active"),
                    "company_names": contact.get("company_names") or [],
                }
                for contact in related_contacts
            ],
            "last_call": last_call_data,
        }
