"""Pydantic models for the configuration backup/restore file format."""

from __future__ import annotations

from enum import Enum
from typing import Any

from pydantic import BaseModel, Field


class SecretsMode(str, Enum):
    EXCLUDE = "exclude"
    MASKED = "masked"
    INCLUDE = "include"


class ConflictMode(str, Enum):
    SKIP = "skip"
    RENAME = "rename"
    OVERWRITE = "overwrite"


class BackupCategory(str, Enum):
    PROVIDERS = "providers"
    TELEGRAM_BOTS = "telegram_bots"
    MATRIX_BOTS = "matrix_bots"
    EMAIL_BOTS = "email_bots"
    TARGETS = "targets"
    TRACKING_CONFIGS = "tracking_configs"
    TEMPLATE_CONFIGS = "template_configs"
    COMMAND_CONFIGS = "command_configs"
    COMMAND_TEMPLATE_CONFIGS = "command_template_configs"
    NOTIFICATION_TRACKERS = "notification_trackers"
    COMMAND_TRACKERS = "command_trackers"
    ACTIONS = "actions"
    APP_SETTINGS = "app_settings"


ALL_CATEGORIES = list(BackupCategory)

# Secret fields in provider config dicts
PROVIDER_SECRET_FIELDS = frozenset(
    ("api_key", "api_token", "webhook_secret", "password",
     "client_secret", "refresh_token")
)


# ---------- nested child models ----------

class ReceiverData(BaseModel):
    name: str = ""
    config: dict[str, Any] = {}
    receiver_key: str = ""
    locale: str = ""
    enabled: bool = True


class TargetData(BaseModel):
    id: int
    type: str
    name: str
    icon: str = ""
    config: dict[str, Any] = {}
    chat_action: str | None = "typing"
    receivers: list[ReceiverData] = []


class TemplateSlotData(BaseModel):
    slot_name: str
    locale: str = "en"
    template: str = ""


class TemplateConfigData(BaseModel):
    id: int
    provider_type: str
    name: str
    description: str = ""
    icon: str = ""
    locale: str = ""
    date_format: str = "%d.%m.%Y, %H:%M UTC"
    date_only_format: str = "%d.%m.%Y"
    slots: list[TemplateSlotData] = []


class CommandTemplateSlotData(BaseModel):
    slot_name: str
    locale: str = "en"
    template: str = ""


class CommandTemplateConfigData(BaseModel):
    id: int
    provider_type: str
    name: str
    description: str = ""
    icon: str = ""
    locale: str = ""
    slots: list[CommandTemplateSlotData] = []


class TrackerTargetData(BaseModel):
    target_id: int
    tracking_config_id: int | None = None
    template_config_id: int | None = None
    enabled: bool = True
    quiet_hours_start: str | None = None
    quiet_hours_end: str | None = None


class NotificationTrackerData(BaseModel):
    id: int
    provider_id: int
    name: str
    icon: str = ""
    collection_ids: list[str] = []
    filters: dict[str, Any] = {}
    scan_interval: int = 60
    default_tracking_config_id: int | None = None
    default_template_config_id: int | None = None
    enabled: bool = True
    targets: list[TrackerTargetData] = []


class CommandTrackerListenerData(BaseModel):
    listener_type: str
    listener_id: int


class CommandTrackerData(BaseModel):
    id: int
    provider_id: int
    command_config_id: int
    name: str
    icon: str = ""
    enabled: bool = True
    listeners: list[CommandTrackerListenerData] = []


class ActionRuleData(BaseModel):
    name: str = ""
    rule_config: dict[str, Any] = {}
    enabled: bool = True
    order: int = 0


class ActionData(BaseModel):
    id: int
    provider_id: int
    name: str
    icon: str = ""
    action_type: str
    config: dict[str, Any] = {}
    schedule_type: str = "interval"
    schedule_interval: int = 3600
    schedule_cron: str = ""
    enabled: bool = False
    rules: list[ActionRuleData] = []


class ProviderData(BaseModel):
    id: int
    type: str
    name: str
    icon: str = ""
    config: dict[str, Any] = {}


class TelegramBotData(BaseModel):
    id: int
    name: str
    token: str = ""
    icon: str = ""
    bot_username: str = ""
    update_mode: str = "none"


class MatrixBotData(BaseModel):
    id: int
    name: str
    icon: str = ""
    homeserver_url: str = ""
    access_token: str = ""
    display_name: str = ""


class EmailBotData(BaseModel):
    id: int
    name: str
    icon: str = ""
    email: str = ""
    smtp_host: str = ""
    smtp_port: int = 587
    smtp_username: str = ""
    smtp_password: str = ""
    smtp_use_tls: bool = True


class TrackingConfigData(BaseModel):
    id: int
    provider_type: str
    name: str
    icon: str = ""
    # All the boolean / int / str tracking fields are captured generically
    fields: dict[str, Any] = {}


class CommandConfigData(BaseModel):
    id: int
    provider_type: str
    name: str
    icon: str = ""
    enabled_commands: list[str] = []
    response_mode: str = "media"
    default_count: int = 5
    rate_limits: dict[str, Any] = {}
    command_template_config_id: int | None = None


class AppSettingData(BaseModel):
    key: str
    value: str = ""


# ---------- top-level backup envelope ----------

class BackupData(BaseModel):
    providers: list[ProviderData] = []
    telegram_bots: list[TelegramBotData] = []
    matrix_bots: list[MatrixBotData] = []
    email_bots: list[EmailBotData] = []
    targets: list[TargetData] = []
    tracking_configs: list[TrackingConfigData] = []
    template_configs: list[TemplateConfigData] = []
    command_configs: list[CommandConfigData] = []
    command_template_configs: list[CommandTemplateConfigData] = []
    notification_trackers: list[NotificationTrackerData] = []
    command_trackers: list[CommandTrackerData] = []
    actions: list[ActionData] = []
    app_settings: list[AppSettingData] = []


class BackupFile(BaseModel):
    format: str = "notify-bridge-backup"
    version: int = 1
    created_at: str = ""
    app_version: str = ""
    secrets_mode: SecretsMode = SecretsMode.EXCLUDE
    categories: list[str] = []
    data: BackupData = Field(default_factory=BackupData)


# ---------- import result ----------

class ImportResult(BaseModel):
    created: int = 0
    skipped: int = 0
    overwritten: int = 0
    errors: list[str] = []
    warnings: list[str] = []


class ValidateResult(BaseModel):
    valid: bool = True
    version: int = 0
    entity_counts: dict[str, int] = {}
    warnings: list[str] = []
    errors: list[str] = []
