# handlers/admin/kyc_review.py

from __future__ import annotations

import asyncio
import logging
import sqlite3
from html import escape
from pathlib import Path
from typing import Any, Optional

from aiogram import F, Router
from aiogram.exceptions import (
    TelegramBadRequest,
    TelegramForbiddenError,
)
from aiogram.fsm.context import FSMContext
from aiogram.types import (
    CallbackQuery,
    InlineKeyboardButton,
    InlineKeyboardMarkup,
    Message,
)
from aiogram.utils.keyboard import InlineKeyboardBuilder

from core.config import settings
from core.ui_emojis import (
    ce,
    emoji_id,
    premiumize_html,
)
from keyboards.admin_kb import (
    get_admin_back_keyboard,
    get_admin_kyc_review_keyboard,
    get_admin_main_menu,
)

from states.admin import AdminKYCStates


logger = logging.getLogger(__name__)

router = Router(
    name="admin_kyc_review"
)

ITEMS_PER_PAGE = 5


# ============================================================
# Configuration
# ============================================================

def get_database_path() -> str:
    value = (
        getattr(
            settings,
            "DB_PATH",
            None,
        )
        or getattr(
            settings,
            "DATABASE_PATH",
            None,
        )
        or "matrix_bot.db"
    )

    return str(value)


DB_PATH = get_database_path()


# ============================================================
# Admin Access
# ============================================================

def get_admin_ids() -> frozenset[int]:
    method = getattr(
        settings,
        "get_admin_list",
        None,
    )

    if callable(method):
        try:
            return frozenset(
                int(user_id)
                for user_id in method()
                if int(user_id) > 0
            )

        except Exception:
            logger.exception(
                "Could not parse ADMIN_IDS "
                "using settings.get_admin_list()."
            )

    raw = str(
        getattr(
            settings,
            "ADMIN_IDS",
            "",
        )
        or ""
    )

    result: set[int] = set()

    for item in raw.split(","):
        item = item.strip()

        if not item:
            continue

        try:
            user_id = int(item)

            if user_id > 0:
                result.add(
                    user_id
                )

        except ValueError:
            logger.warning(
                "Invalid ADMIN_IDS entry ignored: %r",
                item,
            )

    return frozenset(
        result
    )


async def verify_admin_access(
    user_id: int | None,
) -> bool:
    try:
        user_id = int(
            user_id or 0
        )

    except (
        TypeError,
        ValueError,
    ):
        return False

    return (
        user_id > 0
        and user_id in get_admin_ids()
    )


async def require_admin_callback(
    callback: CallbackQuery,
) -> bool:
    user = callback.from_user

    if (
        not user
        or not await verify_admin_access(
            user.id
        )
    ):
        logger.warning(
            "Unauthorized KYC admin callback | "
            "user_id=%s callback=%s",
            (
                user.id
                if user
                else None
            ),
            callback.data,
        )

        try:
            await callback.answer(
                "⛔ دسترسی مدیریت ندارید.",
                show_alert=True,
            )
        except Exception:
            pass

        return False

    return True


async def require_admin_message(
    message: Message,
) -> bool:
    user = message.from_user

    if (
        not user
        or not await verify_admin_access(
            user.id
        )
    ):
        logger.warning(
            "Unauthorized KYC admin message | user_id=%s",
            (
                user.id
                if user
                else None
            ),
        )

        return False

    return True


# ============================================================
# Database
# ============================================================

def _connect() -> sqlite3.Connection:
    conn = sqlite3.connect(
        DB_PATH,
        timeout=30,
        check_same_thread=False,
    )

    conn.row_factory = sqlite3.Row

    conn.execute(
        "PRAGMA busy_timeout = 30000"
    )
    conn.execute(
        "PRAGMA foreign_keys = ON"
    )

    return conn


def _table_exists(
    conn: sqlite3.Connection,
    table_name: str,
) -> bool:
    row = conn.execute(
        """
        SELECT 1
        FROM sqlite_master
        WHERE type = 'table'
          AND name = ?
        LIMIT 1
        """,
        (table_name,),
    ).fetchone()

    return row is not None


def _column_names(
    conn: sqlite3.Connection,
    table_name: str,
) -> set[str]:
    if not _table_exists(
        conn,
        table_name,
    ):
        return set()

    return {
        str(row["name"])
        for row in conn.execute(
            f"PRAGMA table_info({table_name})"
        ).fetchall()
    }


async def ensure_kyc_schema() -> None:
    await asyncio.to_thread(
        _ensure_kyc_schema_sync
    )


def _ensure_kyc_schema_sync() -> None:
    """
    جدول مستقل KYC.

    این جدول فقط metadata/file_id تلگرام را ذخیره می‌کند؛
    فایل واقعی همچنان روی Telegram نگه‌داری می‌شود.
    """
    conn = _connect()

    try:
        conn.execute(
            """
            CREATE TABLE IF NOT EXISTS kyc_requests (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                file_id TEXT NOT NULL,
                status TEXT NOT NULL DEFAULT 'pending',
                reviewed_by INTEGER,
                rejection_reason TEXT,
                warning_text TEXT,
                created_at TIMESTAMP NOT NULL
                    DEFAULT CURRENT_TIMESTAMP,
                reviewed_at TIMESTAMP,
                updated_at TIMESTAMP NOT NULL
                    DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (user_id)
                    REFERENCES users(user_id)
                    ON DELETE CASCADE
            )
            """
        )

        conn.execute(
            """
            CREATE INDEX IF NOT EXISTS
            idx_kyc_requests_user_id
            ON kyc_requests(user_id)
            """
        )

        conn.execute(
            """
            CREATE INDEX IF NOT EXISTS
            idx_kyc_requests_status
            ON kyc_requests(status)
            """
        )

        conn.execute(
            """
            CREATE INDEX IF NOT EXISTS
            idx_kyc_requests_created_at
            ON kyc_requests(created_at)
            """
        )

        conn.commit()

    finally:
        conn.close()


# ============================================================
# KYC Queries
# ============================================================

async def get_pending_kyc_count() -> int:
    await ensure_kyc_schema()

    return await asyncio.to_thread(
        _get_pending_kyc_count_sync
    )


def _get_pending_kyc_count_sync() -> int:
    conn = _connect()

    try:
        row = conn.execute(
            """
            SELECT COUNT(*)
            FROM kyc_requests
            WHERE status = 'pending'
            """
        ).fetchone()

        return int(
            row[0] or 0
        )

    finally:
        conn.close()


async def get_pending_kyc_users(
    page: int,
    per_page: int = ITEMS_PER_PAGE,
) -> list[dict[str, Any]]:
    await ensure_kyc_schema()

    page = max(
        1,
        int(page),
    )

    per_page = max(
        1,
        min(
            int(per_page),
            50,
        ),
    )

    offset = (
        page - 1
    ) * per_page

    return await asyncio.to_thread(
        _get_pending_kyc_users_sync,
        offset,
        per_page,
    )


def _get_pending_kyc_users_sync(
    offset: int,
    limit: int,
) -> list[dict[str, Any]]:
    conn = _connect()

    try:
        rows = conn.execute(
            """
            SELECT
                k.id AS request_id,
                k.user_id,
                k.file_id,
                k.status,
                k.created_at,
                u.username,
                u.full_name
            FROM kyc_requests AS k
            LEFT JOIN users AS u
                ON u.user_id = k.user_id
            WHERE k.status = 'pending'
            ORDER BY k.id ASC
            LIMIT ? OFFSET ?
            """,
            (
                limit,
                offset,
            ),
        ).fetchall()

        return [
            dict(row)
            for row in rows
        ]

    finally:
        conn.close()


async def get_kyc_details(
    user_id: int,
) -> Optional[dict[str, Any]]:
    await ensure_kyc_schema()

    return await asyncio.to_thread(
        _get_kyc_details_sync,
        int(user_id),
    )


def _get_kyc_details_sync(
    user_id: int,
) -> Optional[dict[str, Any]]:
    conn = _connect()

    try:
        row = conn.execute(
            """
            SELECT
                k.id AS request_id,
                k.user_id,
                k.file_id,
                k.status,
                k.reviewed_by,
                k.rejection_reason,
                k.warning_text,
                k.created_at,
                k.reviewed_at,
                k.updated_at,
                u.username,
                u.full_name
            FROM kyc_requests AS k
            LEFT JOIN users AS u
                ON u.user_id = k.user_id
            WHERE k.user_id = ?
            ORDER BY
                CASE
                    WHEN k.status = 'pending'
                    THEN 0
                    ELSE 1
                END,
                k.id DESC
            LIMIT 1
            """,
            (user_id,),
        ).fetchone()

        if not row:
            return None

        data = dict(
            row
        )

        data["submitted_at"] = data.get(
            "created_at"
        )

        data["document_type"] = (
            "تصویر مدرک شناسایی"
        )

        return data

    finally:
        conn.close()


async def update_kyc_status(
    user_id: int,
    status: str,
    admin_id: int,
    reason: Optional[str] = None,
) -> bool:
    """
    تغییر وضعیت به شکل Transactional.

    approved:
        kyc_requests.status = approved
        users.is_kyc_verified = 1

    rejected:
        kyc_requests.status = rejected
        users.is_kyc_verified = 0
    """
    status = str(
        status
    ).strip().lower()

    if status not in {
        "approved",
        "rejected",
        "pending",
    }:
        raise ValueError(
            "Invalid KYC status."
        )

    await ensure_kyc_schema()

    return await asyncio.to_thread(
        _update_kyc_status_sync,
        int(user_id),
        status,
        int(admin_id),
        (
            str(reason).strip()
            if reason
            else None
        ),
    )


def _update_kyc_status_sync(
    user_id: int,
    status: str,
    admin_id: int,
    reason: Optional[str],
) -> bool:
    conn = _connect()

    try:
        conn.execute(
            "BEGIN IMMEDIATE"
        )

        request = conn.execute(
            """
            SELECT id, status
            FROM kyc_requests
            WHERE user_id = ?
            ORDER BY
                CASE
                    WHEN status = 'pending'
                    THEN 0
                    ELSE 1
                END,
                id DESC
            LIMIT 1
            """,
            (user_id,),
        ).fetchone()

        if not request:
            conn.rollback()
            return False

        request_id = int(
            request["id"]
        )

        conn.execute(
            """
            UPDATE kyc_requests
            SET
                status = ?,
                reviewed_by = ?,
                rejection_reason = ?,
                reviewed_at = CURRENT_TIMESTAMP,
                updated_at = CURRENT_TIMESTAMP
            WHERE id = ?
            """,
            (
                status,
                admin_id,
                reason,
                request_id,
            ),
        )

        user_columns = _column_names(
            conn,
            "users",
        )

        if "is_kyc_verified" in user_columns:
            conn.execute(
                """
                UPDATE users
                SET
                    is_kyc_verified = ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE user_id = ?
                """,
                (
                    1
                    if status == "approved"
                    else 0,
                    user_id,
                ),
            )

        elif "kyc_status" in user_columns:
            conn.execute(
                """
                UPDATE users
                SET
                    kyc_status = ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE user_id = ?
                """,
                (
                    status,
                    user_id,
                ),
            )

        # Audit log اگر جدول پروژه موجود باشد.
        if _table_exists(
            conn,
            "audit_logs",
        ):
            audit_columns = _column_names(
                conn,
                "audit_logs",
            )

            if {
                "user_id",
                "action",
                "details",
            }.issubset(
                audit_columns
            ):
                conn.execute(
                    """
                    INSERT INTO audit_logs (
                        user_id,
                        action,
                        details
                    )
                    VALUES (?, ?, ?)
                    """,
                    (
                        admin_id,
                        f"kyc_{status}",
                        (
                            f"target_user_id={user_id}; "
                            f"request_id={request_id}; "
                            f"reason={reason or '-'}"
                        ),
                    ),
                )

        conn.commit()

        logger.info(
            "KYC status updated | "
            "user=%s request=%s status=%s admin=%s",
            user_id,
            request_id,
            status,
            admin_id,
        )

        return True

    except Exception:
        conn.rollback()

        logger.exception(
            "Could not update KYC status | "
            "user=%s status=%s",
            user_id,
            status,
        )

        return False

    finally:
        conn.close()


async def save_warning(
    user_id: int,
    admin_id: int,
    warning_text: str,
) -> None:
    await ensure_kyc_schema()

    await asyncio.to_thread(
        _save_warning_sync,
        int(user_id),
        int(admin_id),
        str(warning_text).strip(),
    )


def _save_warning_sync(
    user_id: int,
    admin_id: int,
    warning_text: str,
) -> None:
    conn = _connect()

    try:
        conn.execute(
            "BEGIN IMMEDIATE"
        )

        row = conn.execute(
            """
            SELECT id
            FROM kyc_requests
            WHERE user_id = ?
            ORDER BY
                CASE
                    WHEN status = 'pending'
                    THEN 0
                    ELSE 1
                END,
                id DESC
            LIMIT 1
            """,
            (user_id,),
        ).fetchone()

        if row:
            conn.execute(
                """
                UPDATE kyc_requests
                SET
                    warning_text = ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
                """,
                (
                    warning_text,
                    int(row["id"]),
                ),
            )

        if _table_exists(
            conn,
            "audit_logs",
        ):
            columns = _column_names(
                conn,
                "audit_logs",
            )

            if {
                "user_id",
                "action",
                "details",
            }.issubset(
                columns
            ):
                conn.execute(
                    """
                    INSERT INTO audit_logs (
                        user_id,
                        action,
                        details
                    )
                    VALUES (?, ?, ?)
                    """,
                    (
                        admin_id,
                        "kyc_warning",
                        (
                            f"target_user_id={user_id}; "
                            f"warning={warning_text}"
                        ),
                    ),
                )

        conn.commit()

    except Exception:
        conn.rollback()
        raise

    finally:
        conn.close()


# ============================================================
# Callback Parsing
# ============================================================

def parse_user_id(
    callback_data: Optional[str],
    prefix: str,
) -> Optional[int]:
    if (
        not callback_data
        or not callback_data.startswith(
            prefix
        )
    ):
        return None

    try:
        value = int(
            callback_data[
                len(prefix):
            ]
        )

        return (
            value
            if value > 0
            else None
        )

    except (
        ValueError,
        TypeError,
    ):
        return None


# ============================================================
# Styled KYC Keyboards
# ============================================================

def _button(
    *,
    text: str,
    callback_data: str,
    style: str = "primary",
    icon: str | None = None,
) -> InlineKeyboardButton:
    if style not in {
        "primary",
        "success",
        "danger",
    }:
        raise ValueError(
            "Invalid button style."
        )

    if len(
        callback_data.encode(
            "utf-8"
        )
    ) > 64:
        raise ValueError(
            "callback_data too long."
        )

    if not icon:
        if style == "success":
            icon = emoji_id(
                "success"
            )
        elif style == "danger":
            icon = emoji_id(
                "error"
            )
        else:
            icon = emoji_id(
                "sparkles"
            )

    return InlineKeyboardButton(
        text=text,
        callback_data=callback_data,
        style=style,
        icon_custom_emoji_id=icon,
    )


def get_kyc_menu_keyboard(
    pending_count: int,
) -> InlineKeyboardMarkup:
    builder = InlineKeyboardBuilder()

    builder.row(
        _button(
            text=(
                "صف درخواست‌های KYC"
                f" ({int(pending_count):,})"
            ),
            callback_data="admin_kyc_queue",
            style=(
                "success"
                if pending_count > 0
                else "primary"
            ),
            icon=emoji_id(
                "package"
            ),
        )
    )

    builder.row(
        _button(
            text="بروزرسانی",
            callback_data="admin_kyc_menu",
            style="primary",
            icon=emoji_id(
                "sparkles"
            ),
        )
    )

    builder.row(
        _button(
            text="بازگشت به پنل مدیریت",
            callback_data="admin_main",
            style="primary",
            icon=emoji_id(
                "back"
            ),
        )
    )

    return builder.as_markup()


def get_kyc_list_keyboard(
    users: list[dict[str, Any]],
    *,
    page: int,
    total_pages: int,
) -> InlineKeyboardMarkup:
    builder = InlineKeyboardBuilder()

    for item in users:
        user_id = int(
            item["user_id"]
        )

        username = item.get(
            "username"
        )

        label = (
            f"@{username}"
            if username
            else f"کاربر {user_id}"
        )

        builder.row(
            _button(
                text=label[:40],
                callback_data=(
                    f"kyc_view_{user_id}"
                ),
                style="primary",
                icon=emoji_id(
                    "user"
                ),
            )
        )

    nav: list[
        InlineKeyboardButton
    ] = []

    if page > 1:
        nav.append(
            _button(
                text="قبلی",
                callback_data=(
                    "kyc_list_page_"
                    f"{page - 1}"
                ),
                style="primary",
                icon=emoji_id(
                    "back"
                ),
            )
        )

    nav.append(
        _button(
            text=(
                f"{page} / "
                f"{total_pages}"
            ),
            callback_data="noop",
            style="primary",
            icon=emoji_id(
                "list"
            ),
        )
    )

    if page < total_pages:
        nav.append(
            _button(
                text="بعدی",
                callback_data=(
                    "kyc_list_page_"
                    f"{page + 1}"
                ),
                style="primary",
                icon=emoji_id(
                    "bolt"
                ),
            )
        )

    builder.row(
        *nav
    )

    builder.row(
        _button(
            text="بازگشت به KYC",
            callback_data="admin_kyc_menu",
            style="primary",
            icon=emoji_id(
                "back"
            ),
        )
    )

    return builder.as_markup()


def get_cancel_input_keyboard() -> InlineKeyboardMarkup:
    builder = InlineKeyboardBuilder()

    builder.row(
        _button(
            text="لغو عملیات",
            callback_data="admin_kyc_cancel_input",
            style="danger",
            icon=emoji_id(
                "error"
            ),
        )
    )

    builder.row(
        _button(
            text="بازگشت به KYC",
            callback_data="admin_kyc_menu",
            style="primary",
            icon=emoji_id(
                "back"
            ),
        )
    )

    return builder.as_markup()


# ============================================================
# Telegram Helpers
# ============================================================

async def safe_callback_answer(
    callback: CallbackQuery,
    text: str | None = None,
    *,
    show_alert: bool = False,
) -> None:
    try:
        await callback.answer(
            text=text,
            show_alert=show_alert,
        )

    except TelegramBadRequest:
        pass

    except Exception:
        logger.exception(
            "Could not answer KYC callback."
        )


async def safe_edit_message(
    callback: CallbackQuery,
    text: str,
    reply_markup=None,
) -> bool:
    if not callback.message:
        return False

    try:
        await callback.message.edit_text(
            text=premiumize_html(
                text
            ),
            reply_markup=reply_markup,
            parse_mode="HTML",
        )

        return True

    except TelegramBadRequest as exc:
        error = str(
            exc
        ).lower()

        if (
            "message is not modified"
            in error
        ):
            return True

        if (
            "message can't be edited"
            in error
            or "message to edit not found"
            in error
        ):
            try:
                await callback.message.answer(
                    premiumize_html(
                        text
                    ),
                    reply_markup=reply_markup,
                    parse_mode="HTML",
                )

                return True

            except Exception:
                logger.exception(
                    "Could not send replacement KYC message."
                )

                return False

        logger.warning(
            "Could not edit KYC message: %s",
            exc,
        )

        return False

    except Exception:
        logger.exception(
            "Unexpected KYC edit error."
        )

        return False


async def send_html(
    message: Message,
    text: str,
    *,
    reply_markup=None,
) -> None:
    await message.answer(
        premiumize_html(
            text
        ),
        reply_markup=reply_markup,
        parse_mode="HTML",
    )


async def notify_user(
    bot,
    user_id: int,
    text: str,
) -> bool:
    try:
        await bot.send_message(
            chat_id=user_id,
            text=premiumize_html(
                text
            ),
            parse_mode="HTML",
        )

        return True

    except TelegramForbiddenError:
        logger.warning(
            "User %s blocked the bot.",
            user_id,
        )

        return False

    except Exception:
        logger.exception(
            "Could not notify KYC user %s.",
            user_id,
        )

        return False


# ============================================================
# KYC Main Menu
# ============================================================

@router.callback_query(
    F.data == "admin_kyc_menu"
)
async def admin_kyc_menu_handler(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    try:
        await state.clear()

        pending_count = (
            await get_pending_kyc_count()
        )

        text = (
            f"{ce('sparkles')} "
            "<b>مدیریت احراز هویت KYC</b>\n"
            "━━━━━━━━━━━━━━━━━━━━\n\n"

            f"{ce('loading')} "
            "درخواست‌های در انتظار بررسی: "
            f"<code>{pending_count:,}</code>\n\n"

            f"{ce('target')} "
            "بخش مورد نظر را انتخاب کنید."
        )

        await safe_edit_message(
            callback,
            text,
            get_kyc_menu_keyboard(
                pending_count
            ),
        )

        await safe_callback_answer(
            callback
        )

    except Exception:
        logger.exception(
            "Error in admin_kyc_menu_handler"
        )

        await safe_callback_answer(
            callback,
            "❌ خطا در بارگذاری بخش احراز هویت.",
            show_alert=True,
        )


# ============================================================
# KYC Queue
# ============================================================

@router.callback_query(
    F.data == "admin_kyc_queue"
)
async def admin_kyc_queue_handler(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    await show_kyc_page(
        callback=callback,
        state=state,
        page=1,
    )


@router.callback_query(
    F.data.startswith(
        "kyc_list_page_"
    )
)
async def paginate_kyc_list(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    try:
        page = int(
            str(
                callback.data
            ).rsplit(
                "_",
                1,
            )[-1]
        )

    except (
        ValueError,
        AttributeError,
    ):
        await safe_callback_answer(
            callback,
            "❌ شماره صفحه نامعتبر است.",
            show_alert=True,
        )
        return

    await show_kyc_page(
        callback=callback,
        state=state,
        page=max(
            page,
            1,
        ),
    )


async def show_kyc_page(
    callback: CallbackQuery,
    state: FSMContext,
    page: int,
):
    try:
        await state.clear()

        pending_count = (
            await get_pending_kyc_count()
        )

        total_pages = max(
            1,
            (
                pending_count
                + ITEMS_PER_PAGE
                - 1
            )
            // ITEMS_PER_PAGE,
        )

        page = max(
            1,
            min(
                int(page),
                total_pages,
            ),
        )

        users = (
            await get_pending_kyc_users(
                page=page,
                per_page=ITEMS_PER_PAGE,
            )
        )

        if not users:
            text = (
                f"{ce('list')} "
                "<b>صف بررسی احراز هویت</b>\n"
                "━━━━━━━━━━━━━━━━━━━━\n\n"
                f"{ce('success')} "
                "در حال حاضر درخواست KYC معلقی وجود ندارد."
            )

        else:
            lines = [
                (
                    f"{ce('list')} "
                    "<b>درخواست‌های احراز هویت</b>"
                ),
                "━━━━━━━━━━━━━━━━━━━━",
                (
                    f"{ce('history')} صفحه "
                    f"<code>{page}</code> از "
                    f"<code>{total_pages}</code>"
                ),
                "",
            ]

            start_index = (
                page - 1
            ) * ITEMS_PER_PAGE

            for index, item in enumerate(
                users,
                start=start_index + 1,
            ):
                user_id = int(
                    item["user_id"]
                )

                username = (
                    item.get(
                        "username"
                    )
                    or ""
                )

                full_name = (
                    item.get(
                        "full_name"
                    )
                    or "بدون نام"
                )

                display_name = (
                    f"@{username}"
                    if username
                    else full_name
                )

                lines.append(
                    (
                        f"{index}. "
                        f"{ce('user')} "
                        f"<b>{escape(str(display_name))}</b>\n"
                        f"   ID: <code>{user_id}</code>"
                    )
                )

            text = "\n\n".join(
                lines
            )

        await safe_edit_message(
            callback,
            text,
            get_kyc_list_keyboard(
                users,
                page=page,
                total_pages=total_pages,
            ),
        )

        await safe_callback_answer(
            callback
        )

    except Exception:
        logger.exception(
            "Error rendering KYC page"
        )

        await safe_callback_answer(
            callback,
            "❌ خطا در بارگذاری لیست احراز هویت.",
            show_alert=True,
        )


# ============================================================
# KYC Details
# ============================================================

@router.callback_query(
    F.data.startswith(
        "kyc_view_"
    )
)
async def view_kyc_details(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    user_id = parse_user_id(
        callback.data,
        "kyc_view_",
    )

    if not user_id:
        await safe_callback_answer(
            callback,
            "❌ شناسه کاربر نامعتبر است.",
            show_alert=True,
        )
        return

    try:
        await state.clear()

        kyc = await get_kyc_details(
            user_id
        )

        if not kyc:
            await safe_callback_answer(
                callback,
                "❌ پرونده KYC پیدا نشد.",
                show_alert=True,
            )
            return

        username = (
            kyc.get(
                "username"
            )
            or ""
        )

        full_name = (
            kyc.get(
                "full_name"
            )
            or "نامشخص"
        )

        status = (
            kyc.get(
                "status"
            )
            or "unknown"
        )

        submitted_at = (
            kyc.get(
                "submitted_at"
            )
            or "نامشخص"
        )

        request_id = (
            kyc.get(
                "request_id"
            )
            or "-"
        )

        username_text = (
            f"@{username}"
            if username
            else "ثبت نشده"
        )

        caption = (
            f"{ce('package')} "
            "<b>پرونده احراز هویت کاربر</b>\n"
            "━━━━━━━━━━━━━━━━━━━━\n\n"

            f"{ce('list')} درخواست: "
            f"<code>#{escape(str(request_id))}</code>\n"

            f"{ce('user')} شناسه: "
            f"<code>{user_id}</code>\n"

            f"{ce('user')} نام: "
            f"<b>{escape(str(full_name))}</b>\n"

            f"{ce('chat')} یوزرنیم: "
            f"<code>{escape(str(username_text))}</code>\n"

            f"{ce('history')} تاریخ ارسال: "
            f"<code>{escape(str(submitted_at))}</code>\n"

            f"{ce('pin')} وضعیت: "
            f"<code>{escape(str(status))}</code>\n\n"

            f"{ce('target')} "
            "مدرک را بررسی و نتیجه را انتخاب کنید."
        )

        file_id = (
            kyc.get(
                "file_id"
            )
            or ""
        )

        # اگر Telegram file_id موجود است، خود مدرک را نمایش بده.
        if file_id:
            try:
                await callback.bot.send_photo(
                    chat_id=(
                        callback.from_user.id
                    ),
                    photo=file_id,
                    caption=premiumize_html(
                        caption
                    ),
                    reply_markup=(
                        get_admin_kyc_review_keyboard(
                            user_id
                        )
                    ),
                    parse_mode="HTML",
                )

                await safe_callback_answer(
                    callback,
                    "پرونده ارسال شد."
                )

                return

            except TelegramBadRequest:
                logger.exception(
                    "Could not send KYC photo | user=%s",
                    user_id,
                )

        # fallback if photo unavailable
        await safe_edit_message(
            callback,
            caption,
            get_admin_kyc_review_keyboard(
                user_id
            ),
        )

        await safe_callback_answer(
            callback
        )

    except Exception:
        logger.exception(
            "Error viewing KYC details for %s",
            user_id,
        )

        await safe_callback_answer(
            callback,
            "❌ خطا در بارگذاری پرونده.",
            show_alert=True,
        )


# ============================================================
# Approve KYC
# ============================================================

@router.callback_query(
    F.data.startswith(
        "kyc_approve_"
    )
)
async def approve_kyc_handler(
    callback: CallbackQuery,
):
    if not await require_admin_callback(
        callback
    ):
        return

    user_id = parse_user_id(
        callback.data,
        "kyc_approve_",
    )

    if not user_id:
        await safe_callback_answer(
            callback,
            "❌ شناسه کاربر نامعتبر است.",
            show_alert=True,
        )
        return

    admin_id = int(
        callback.from_user.id
    )

    try:
        success = await update_kyc_status(
            user_id=user_id,
            status="approved",
            admin_id=admin_id,
        )

        if not success:
            await safe_callback_answer(
                callback,
                "❌ پرونده قابل تایید پیدا نشد.",
                show_alert=True,
            )
            return

        notification_sent = await notify_user(
            callback.bot,
            user_id,
            (
                f"{ce('success')} "
                "<b>احراز هویت شما تایید شد.</b>\n\n"
                "مدارک شما با موفقیت بررسی شد و "
                "وضعیت حساب شما تایید گردید."
            ),
        )

        text = (
            f"{ce('success')} "
            "<b>احراز هویت تایید شد</b>\n\n"
            f"{ce('user')} کاربر: "
            f"<code>{user_id}</code>\n"
            f"{ce('users')} بررسی‌کننده: "
            f"<code>{admin_id}</code>\n"
            f"{ce('pin')} وضعیت: "
            "<code>approved</code>\n\n"
            + (
                f"{ce('chat')} "
                "پیام نتیجه برای کاربر ارسال شد."
                if notification_sent
                else (
                    f"{ce('warning')} "
                    "وضعیت ثبت شد ولی کاربر پیام را دریافت نکرد."
                )
            )
        )

        await safe_edit_message(
            callback,
            text,
            get_admin_back_keyboard(
                "admin_kyc_queue"
            ),
        )

        await safe_callback_answer(
            callback,
            "✅ احراز هویت تایید شد.",
            show_alert=True,
        )

    except Exception:
        logger.exception(
            "Error approving KYC for %s",
            user_id,
        )

        await safe_callback_answer(
            callback,
            "❌ خطا هنگام تایید احراز هویت.",
            show_alert=True,
        )


# ============================================================
# Reject KYC
# ============================================================

@router.callback_query(
    F.data.startswith(
        "kyc_reject_"
    )
)
async def reject_kyc_prompt_handler(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    user_id = parse_user_id(
        callback.data,
        "kyc_reject_",
    )

    if not user_id:
        await safe_callback_answer(
            callback,
            "❌ شناسه کاربر نامعتبر است.",
            show_alert=True,
        )
        return

    try:
        await state.set_state(
            AdminKYCStates.waiting_for_reject_reason
        )

        await state.update_data(
            target_user_id=user_id,
            kyc_action="reject",
        )

        text = (
            f"{ce('error')} "
            "<b>رد درخواست احراز هویت</b>\n\n"
            f"{ce('user')} کاربر: "
            f"<code>{user_id}</code>\n\n"
            f"{ce('chat')} "
            "دلیل رد مدارک را ارسال کنید.\n\n"
            f"{ce('warning')} "
            "دلیل برای کاربر نمایش داده می‌شود؛ "
            "واضح و محترمانه بنویسید."
        )

        await safe_edit_message(
            callback,
            text,
            get_cancel_input_keyboard(),
        )

        await safe_callback_answer(
            callback
        )

    except Exception:
        logger.exception(
            "Error starting KYC rejection for %s",
            user_id,
        )

        await safe_callback_answer(
            callback,
            "❌ خطا در شروع فرآیند رد.",
            show_alert=True,
        )


@router.callback_query(
    F.data == "admin_kyc_cancel_input"
)
async def cancel_kyc_input(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    await state.clear()

    await admin_kyc_menu_handler(
        callback,
        state,
    )


@router.callback_query(
    F.data == "admin_confirm_yes_cancel_kyc_reject"
)
async def legacy_cancel_kyc_reject(
    callback: CallbackQuery,
    state: FSMContext,
):
    """
    سازگاری با callback نسخه قدیمی.
    """
    await cancel_kyc_input(
        callback,
        state,
    )


@router.message(
    AdminKYCStates.waiting_for_reject_reason,
    F.text,
)
async def process_kyc_reject_reason(
    message: Message,
    state: FSMContext,
):
    if not await require_admin_message(
        message
    ):
        await state.clear()
        return

    try:
        data = await state.get_data()

        user_id = data.get(
            "target_user_id"
        )

        if not user_id:
            await state.clear()

            await send_html(
                message,
                (
                    f"{ce('warning')} "
                    "نشست شما منقضی شده است.\n"
                    "لطفاً دوباره از پنل مدیریت اقدام کنید."
                ),
                reply_markup=get_admin_main_menu(),
            )
            return

        reason = (
            message.text
            or ""
        ).strip()

        if len(
            reason
        ) < 3:
            await send_html(
                message,
                (
                    f"{ce('error')} "
                    "دلیل رد خیلی کوتاه است.\n"
                    "حداقل ۳ کاراکتر وارد کنید."
                ),
                reply_markup=(
                    get_cancel_input_keyboard()
                ),
            )
            return

        if len(
            reason
        ) > 1000:
            await send_html(
                message,
                (
                    f"{ce('error')} "
                    "دلیل رد نباید بیشتر از "
                    "۱۰۰۰ کاراکتر باشد."
                ),
                reply_markup=(
                    get_cancel_input_keyboard()
                ),
            )
            return

        admin_id = int(
            message.from_user.id
        )

        success = await update_kyc_status(
            user_id=int(
                user_id
            ),
            status="rejected",
            admin_id=admin_id,
            reason=reason,
        )

        if not success:
            await send_html(
                message,
                (
                    f"{ce('error')} "
                    "پرونده KYC برای رد کردن پیدا نشد."
                ),
                reply_markup=get_admin_main_menu(),
            )
            return

        notification_sent = await notify_user(
            message.bot,
            int(user_id),
            (
                f"{ce('error')} "
                "<b>درخواست احراز هویت شما رد شد.</b>\n\n"
                f"{ce('chat')} <b>دلیل رد:</b>\n"
                f"{escape(reason)}\n\n"
                "لطفاً موارد اعلام‌شده را اصلاح کرده و "
                "در صورت امکان مجدداً مدارک را ارسال کنید."
            ),
        )

        await state.clear()

        await send_html(
            message,
            (
                f"{ce('error')} "
                "<b>احراز هویت رد شد.</b>\n\n"
                f"{ce('user')} کاربر: "
                f"<code>{int(user_id)}</code>\n"
                f"{ce('chat')} دلیل: "
                f"<code>{escape(reason)}</code>\n\n"
                + (
                    f"{ce('success')} "
                    "پیام نتیجه برای کاربر ارسال شد."
                    if notification_sent
                    else (
                        f"{ce('warning')} "
                        "وضعیت ثبت شد ولی پیام به کاربر نرسید."
                    )
                )
            ),
            reply_markup=get_admin_back_keyboard(
                "admin_kyc_queue"
            ),
        )

    except Exception:
        logger.exception(
            "Error processing KYC rejection"
        )

        await state.clear()

        await send_html(
            message,
            (
                f"{ce('error')} "
                "خطای غیرمنتظره‌ای هنگام ثبت رد "
                "احراز هویت رخ داد."
            ),
            reply_markup=get_admin_main_menu(),
        )


# ============================================================
# Warn User
# ============================================================

@router.callback_query(
    F.data.startswith(
        "kyc_warn_"
    )
)
async def warn_kyc_user(
    callback: CallbackQuery,
    state: FSMContext,
):
    if not await require_admin_callback(
        callback
    ):
        return

    user_id = parse_user_id(
        callback.data,
        "kyc_warn_",
    )

    if not user_id:
        await safe_callback_answer(
            callback,
            "❌ شناسه کاربر نامعتبر است.",
            show_alert=True,
        )
        return

    await state.set_state(
        AdminKYCStates.waiting_for_warning
    )

    await state.update_data(
        target_user_id=user_id,
        kyc_action="warning",
    )

    text = (
        f"{ce('warning')} "
        "<b>ارسال اخطار برای کاربر</b>\n\n"
        f"{ce('user')} شناسه کاربر: "
        f"<code>{user_id}</code>\n\n"
        f"{ce('chat')} "
        "متن اخطار را ارسال کنید."
    )

    await safe_edit_message(
        callback,
        text,
        get_cancel_input_keyboard(),
    )

    await safe_callback_answer(
        callback
    )


@router.callback_query(
    F.data == "admin_confirm_yes_cancel_kyc_warning"
)
async def legacy_cancel_kyc_warning(
    callback: CallbackQuery,
    state: FSMContext,
):
    """
    سازگاری با callback نسخه قدیمی.
    """
    await cancel_kyc_input(
        callback,
        state,
    )


@router.message(
    AdminKYCStates.waiting_for_warning,
    F.text,
)
async def process_kyc_warning(
    message: Message,
    state: FSMContext,
):
    if not await require_admin_message(
        message
    ):
        await state.clear()
        return

    data = await state.get_data()

    user_id = data.get(
        "target_user_id"
    )

    if not user_id:
        await state.clear()

        await send_html(
            message,
            (
                f"{ce('warning')} "
                "نشست شما منقضی شده است."
            ),
            reply_markup=get_admin_main_menu(),
        )
        return

    warning_text = (
        message.text
        or ""
    ).strip()

    if len(
        warning_text
    ) < 3:
        await send_html(
            message,
            (
                f"{ce('error')} "
                "متن اخطار خیلی کوتاه است."
            ),
            reply_markup=get_cancel_input_keyboard(),
        )
        return

    if len(
        warning_text
    ) > 2000:
        await send_html(
            message,
            (
                f"{ce('error')} "
                "متن اخطار نباید بیشتر از "
                "۲۰۰۰ کاراکتر باشد."
            ),
            reply_markup=get_cancel_input_keyboard(),
        )
        return

    try:
        admin_id = int(
            message.from_user.id
        )

        sent = await notify_user(
            message.bot,
            int(user_id),
            (
                f"{ce('warning')} "
                "<b>اخطار از طرف تیم پشتیبانی</b>\n\n"
                f"{escape(warning_text)}"
            ),
        )

        if sent:
            try:
                await save_warning(
                    int(user_id),
                    admin_id,
                    warning_text,
                )
            except Exception:
                logger.exception(
                    "Could not save KYC warning audit."
                )

            await send_html(
                message,
                (
                    f"{ce('success')} "
                    "اخطار برای کاربر "
                    f"<code>{int(user_id)}</code> "
                    "ارسال شد."
                ),
                reply_markup=get_admin_back_keyboard(
                    "admin_kyc_queue"
                ),
            )

        else:
            await send_html(
                message,
                (
                    f"{ce('warning')} "
                    "ارسال اخطار ممکن نبود؛ "
                    "احتمالاً کاربر ربات را مسدود کرده است."
                ),
                reply_markup=get_admin_back_keyboard(
                    "admin_kyc_queue"
                ),
            )

    except Exception:
        logger.exception(
            "Failed sending KYC warning to %s",
            user_id,
        )

        await send_html(
            message,
            (
                f"{ce('error')} "
                "ارسال اخطار ناموفق بود."
            ),
            reply_markup=get_admin_main_menu(),
        )

    finally:
        await state.clear()