from __future__ import annotations

"""Storage handler for sync configuration and status update."""


import json
import logging
from typing import Any
from uuid import UUID

logger = logging.getLogger(__name__)


class InvoiceStorageSyncConfigMixin:
    """Mixin for managing sync configs."""

    def save_sync_config(
        self,
        service_type: str,
        tax_code: str,
        username: str,
        password: str,
        extra_config: dict[str, Any] | None = None,
        is_active: bool = True,
        user_name: str = "SuperAdmin",
    ) -> dict[str, Any]:
        """Lưu hoặc cập nhật cấu hình tài khoản kết nối thực tế."""
        if not service_type or not tax_code or not username:
            return {
                "status": "error",
                "message": "Vui lòng điền đầy đủ Loại dịch vụ, Mã số thuế và Tên đăng nhập.",
            }

        with self.get_connection() as conn:
            with conn.cursor() as cur:
                sql = """
                    INSERT INTO erp_invoice_sync_configs (
                        service_type, tax_code, username, password_hash, extra_config, is_active,
                        last_sync_status, last_sync_message, created_by, updated_at
                    ) VALUES (
                        %s, %s, %s, %s, %s, %s,
                        'CONFIGURED', 'Đã lưu thông tin cấu hình xác thực.', %s, CURRENT_TIMESTAMP
                    )
                    ON CONFLICT (service_type, tax_code) DO UPDATE
                    SET username = EXCLUDED.username,
                        password_hash = CASE WHEN EXCLUDED.password_hash != '' THEN EXCLUDED.password_hash ELSE erp_invoice_sync_configs.password_hash END,
                        extra_config = EXCLUDED.extra_config,
                        is_active = EXCLUDED.is_active,
                        last_sync_status = 'CONFIGURED',
                        last_sync_message = 'Đã cập nhật cấu hình kết nối mới.',
                        updated_at = CURRENT_TIMESTAMP
                    RETURNING id;
                """
                cfg_extra = dict(extra_config or {})
                cfg_extra["consecutive_auth_failures"] = 0
                cfg_extra.pop("cooldown_until", None)
                cur.execute(
                    sql,
                    (
                        service_type,
                        tax_code,
                        username,
                        password,
                        json.dumps(cfg_extra, ensure_ascii=False),
                        is_active,
                        user_name,
                    ),
                )
                config_id = str(cur.fetchone()["id"])
                conn.commit()
                return {
                    "status": "success",
                    "message": f"Đã lưu cấu hình tài khoản kết nối cho {service_type.upper()} (MST: {tax_code}).",
                    "config_id": config_id,
                }

    def _update_sync_status(self, config_id: UUID, status: str, message: str) -> None:
        """Cập nhật trạng thái lần đồng bộ gần nhất vào bảng erp_invoice_sync_configs."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET last_sync_at = CURRENT_TIMESTAMP,
                            last_sync_status = %s,
                            last_sync_message = %s,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = %s;
                    """,
                    (status, message, config_id),
                )
                conn.commit()
        except Exception:
            pass

    def deactivate_sync_config(
        self,
        service_type: str,
        tax_code: str,
        reason: str = "Tài khoản Cổng Thuế bị tạm khóa do nhập sai nhiều lần. Đang chờ mở khóa tài khoản.",
        status: str = "ACCOUNT_LOCKED",
    ) -> bool:
        """Tạm ngưng / vô hiệu hóa cấu hình đồng bộ hóa đơn (ví dụ khi tài khoản Cổng Thuế bị khóa hoặc Circuit Breaker kích hoạt)."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET is_active = FALSE,
                            last_sync_status = %s,
                            last_sync_message = %s,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (status, reason, service_type, tax_code),
                )
                conn.commit()
                return cur.rowcount > 0
        except Exception as err:
            logger.error("Lỗi khi vô hiệu hóa cấu hình sync %s (%s): %s", service_type, tax_code, err)
            return False

    def activate_sync_config(self, service_type: str, tax_code: str) -> bool:
        """Kích hoạt lại cấu hình đồng bộ sau khi mở khóa tài khoản."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET is_active = TRUE,
                            last_sync_status = 'CONFIGURED',
                            last_sync_message = 'Tài khoản Cổng Thuế đã sẵn sàng đồng bộ an toàn (AI Hawk Stealth & Cooldown 3h).',
                            extra_config = (
                                jsonb_set(
                                    COALESCE(extra_config, '{}'::jsonb),
                                    '{consecutive_auth_failures}',
                                    '0'::jsonb
                                ) - 'cooldown_until'
                            ),
                            updated_at = CURRENT_TIMESTAMP
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (service_type, tax_code),
                )
                conn.commit()
                return cur.rowcount > 0
        except Exception as err:
            logger.error("Lỗi khi kích hoạt lại cấu hình sync %s (%s): %s", service_type, tax_code, err)
            return False

    def increment_auth_failures(self, service_type: str, tax_code: str) -> int:
        """Tăng số lần xác thực thất bại liên tiếp trong extra_config và trả về số lần hiện tại."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET extra_config = jsonb_set(
                            COALESCE(extra_config, '{}'::jsonb),
                            '{consecutive_auth_failures}',
                            (COALESCE((extra_config->>'consecutive_auth_failures')::int, 0) + 1)::text::jsonb
                        ),
                        updated_at = CURRENT_TIMESTAMP
                        WHERE service_type = %s AND tax_code = %s
                        RETURNING COALESCE((extra_config->>'consecutive_auth_failures')::int, 1) AS failures;
                    """,
                    (service_type, tax_code),
                )
                row = cur.fetchone()
                conn.commit()
                if row:
                    return int(row["failures"] if isinstance(row, dict) else row[0])
                return 1
        except Exception as err:
            logger.error("Lỗi khi tăng số lần auth failure cho %s (%s): %s", service_type, tax_code, err)
            return 1

    def reset_auth_failures(self, service_type: str, tax_code: str) -> None:
        """Đặt lại số lần xác thực thất bại liên tiếp về 0 khi kết nối thành công hoặc khôi phục."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET extra_config = (
                            jsonb_set(
                                COALESCE(extra_config, '{}'::jsonb),
                                '{consecutive_auth_failures}',
                                '0'::jsonb
                            ) - 'cooldown_until'
                        ),
                        updated_at = CURRENT_TIMESTAMP
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (service_type, tax_code),
                )
                conn.commit()
        except Exception as err:
            logger.error("Lỗi khi reset auth failure cho %s (%s): %s", service_type, tax_code, err)

    def get_auth_failures(self, service_type: str, tax_code: str) -> int:
        """Lấy số lần xác thực thất bại liên tiếp hiện tại."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        SELECT COALESCE((extra_config->>'consecutive_auth_failures')::int, 0) AS failures
                        FROM erp_invoice_sync_configs
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (service_type, tax_code),
                )
                row = cur.fetchone()
                if row:
                    return int(row["failures"] if isinstance(row, dict) else row[0])
                return 0
        except Exception as err:
            logger.error("Lỗi khi lấy auth failures cho %s (%s): %s", service_type, tax_code, err)
            return 0

    def set_auth_cooldown(
        self, service_type: str, tax_code: str, hours: float = 3.0
    ) -> str:
        """Kích hoạt thời gian khóa chờ an toàn (Cooldown, mặc định 3 giờ) khi xác thực thất bại."""
        from datetime import datetime, timedelta, timezone

        cooldown_until = (
            datetime.now(timezone.utc) + timedelta(hours=hours)
        ).isoformat()
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET extra_config = jsonb_set(
                            COALESCE(extra_config, '{}'::jsonb),
                            '{cooldown_until}',
                            %s::jsonb
                        ),
                        last_sync_status = 'COOLDOWN_ACTIVE',
                        last_sync_message = %s,
                        updated_at = CURRENT_TIMESTAMP
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (
                        json.dumps(cooldown_until),
                        f"Đang trong thời gian chờ an toàn {hours} giờ (đến {cooldown_until}) để chống khóa tài khoản sau lần thử thất bại.",
                        service_type,
                        tax_code,
                    ),
                )
                conn.commit()
                return cooldown_until
        except Exception as err:
            logger.error("Lỗi khi đặt cooldown cho %s (%s): %s", service_type, tax_code, err)
            return cooldown_until

    def check_auth_cooldown(
        self, service_type: str, tax_code: str
    ) -> tuple[bool, str | None]:
        """Kiểm tra xem tài khoản có đang trong thời gian chờ an toàn (3h Cooldown) hay không."""
        from datetime import datetime, timezone

        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        SELECT extra_config->>'cooldown_until' AS cd_until
                        FROM erp_invoice_sync_configs
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (service_type, tax_code),
                )
                row = cur.fetchone()
                if not row:
                    return False, None
                cd_str = row["cd_until"] if isinstance(row, dict) else row[0]
                if not cd_str:
                    return False, None

                cd_time = datetime.fromisoformat(cd_str)
                now_utc = datetime.now(timezone.utc)
                if cd_time.tzinfo is None:
                    cd_time = cd_time.replace(tzinfo=timezone.utc)

                if cd_time > now_utc:
                    return True, cd_str
                return False, None
        except Exception as err:
            logger.error("Lỗi khi kiểm tra cooldown cho %s (%s): %s", service_type, tax_code, err)
            return False, None

    def clear_auth_cooldown(self, service_type: str, tax_code: str) -> None:
        """Xóa thời gian chờ an toàn (khi đăng nhập thành công hoặc quản trị viên khôi phục)."""
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(
                    """
                        UPDATE erp_invoice_sync_configs
                        SET extra_config = extra_config - 'cooldown_until',
                            updated_at = CURRENT_TIMESTAMP
                        WHERE service_type = %s AND tax_code = %s;
                    """,
                    (service_type, tax_code),
                )
                conn.commit()
        except Exception as err:
            logger.error("Lỗi khi xóa cooldown cho %s (%s): %s", service_type, tax_code, err)
