from __future__ import annotations

from datetime import datetime

from sqlalchemy import select

from app.config import Settings
from app.db.models import ReferralCode, ReferralInvite, RemnawaveUser, TelegramUser
from app.schemas.remnawave import PaginatedUsers
from app.services.sync_service import SyncService
from tests.helpers import make_remote_user


class _StubRemnawaveClient:
    def __init__(self, users) -> None:
        self.users = users

    async def get_users_by_telegram_id(self, telegram_id: int):
        return list(self.users)

    async def get_all_users(self, *, start: int = 0, size: int = 100):
        items = list(self.users)[start : start + size]
        return PaginatedUsers(users=items, total=len(self.users))


async def test_refresh_cached_users_clears_stale_links_and_keeps_profile(
    session_factory,
) -> None:
    user_one = make_remote_user(
        user_uuid="44444444-4444-4444-4444-444444444444",
        user_id=4,
        short_uuid="user-one",
        username="oreol-one",
        telegram_id=1001,
    )
    user_two = make_remote_user(
        user_uuid="55555555-5555-5555-5555-555555555555",
        user_id=5,
        short_uuid="user-two",
        username="oreol-two",
        telegram_id=1001,
    )
    client = _StubRemnawaveClient([user_one, user_two])
    service = SyncService(
        settings=Settings.model_construct(
            bot_admin_ids_raw="",
            sync_subscription_history=False,
        ),
        session_factory=session_factory,
        remnawave_client=client,
    )

    await service.sync_users_for_telegram(
        telegram_id=1001,
        username="keeper",
        first_name="Keep",
        last_name="Me",
        language_code="ru",
    )

    client.users = [user_one]
    views = await service.refresh_cached_users_for_telegram(telegram_id=1001)

    assert [view.record.rw_uuid for view in views] == [str(user_one.uuid)]

    async with session_factory() as session:
        telegram_user = await session.scalar(
            select(TelegramUser).where(TelegramUser.telegram_id == 1001)
        )
        stale_user = await session.scalar(
            select(RemnawaveUser).where(RemnawaveUser.rw_uuid == str(user_two.uuid))
        )

    assert telegram_user is not None
    assert telegram_user.username == "keeper"
    assert stale_user is not None
    assert stale_user.telegram_id is None
    assert stale_user.owner_telegram_user_id is None


async def test_get_admin_telegram_users_page_returns_paginated_users(
    session_factory,
) -> None:
    service = SyncService(
        settings=Settings.model_construct(
            bot_admin_ids_raw="",
            sync_subscription_history=False,
        ),
        session_factory=session_factory,
        remnawave_client=_StubRemnawaveClient([]),
    )

    async with session_factory() as session:
        session.add_all(
            [
                TelegramUser(
                    telegram_id=1001,
                    username="first",
                    first_name="First",
                    last_name="User",
                    language_code="ru",
                    last_seen_at=datetime(2026, 4, 21, 10, 0),
                    created_at=datetime(2026, 4, 1, 10, 0),
                    updated_at=datetime(2026, 4, 21, 10, 0),
                ),
                TelegramUser(
                    telegram_id=1002,
                    username="second",
                    first_name="Second",
                    last_name="User",
                    language_code="ru",
                    last_seen_at=datetime(2026, 4, 22, 12, 0),
                    created_at=datetime(2026, 4, 2, 10, 0),
                    updated_at=datetime(2026, 4, 22, 12, 0),
                ),
                TelegramUser(
                    telegram_id=1003,
                    username="third",
                    first_name="Third",
                    last_name="User",
                    language_code="ru",
                    last_seen_at=datetime(2026, 4, 22, 12, 0),
                    created_at=datetime(2026, 4, 3, 10, 0),
                    updated_at=datetime(2026, 4, 22, 12, 0),
                ),
            ]
        )
        await session.commit()

    page_one = await service.get_admin_telegram_users_page(page=1, page_size=2)
    page_two = await service.get_admin_telegram_users_page(page=2, page_size=2)

    assert page_one.total_items == 3
    assert page_one.total_pages == 2
    assert [item.telegram_id for item in page_one.items] == [1003, 1002]
    assert [item.telegram_id for item in page_two.items] == [1001]


async def test_get_admin_telegram_user_profile_returns_referral_and_access_data(
    session_factory,
) -> None:
    remote_user = make_remote_user(
        user_uuid="66666666-6666-6666-6666-666666666666",
        user_id=6,
        short_uuid="profile-user",
        username="oreol-profile",
        telegram_id=2001,
    )
    service = SyncService(
        settings=Settings.model_construct(
            bot_admin_ids_raw="1001",
            sync_subscription_history=False,
        ),
        session_factory=session_factory,
        remnawave_client=_StubRemnawaveClient([remote_user]),
    )

    await service.sync_users_for_telegram(
        telegram_id=2001,
        username="profile",
        first_name="Profile",
        last_name="User",
        language_code="ru",
    )

    async with session_factory() as session:
        session.add(
            TelegramUser(
                telegram_id=1001,
                username="inviter",
                first_name="Inviter",
                last_name="Admin",
                language_code="ru",
                is_admin=True,
                last_seen_at=datetime(2026, 4, 22, 11, 0),
                created_at=datetime(2026, 4, 1, 8, 0),
                updated_at=datetime(2026, 4, 22, 11, 0),
            )
        )
        session.add(
            ReferralCode(telegram_id=1001, code="INVITER1001")
        )
        session.add(
            ReferralCode(telegram_id=2001, code="SELF2001")
        )
        session.add_all(
            [
                ReferralInvite(
                    inviter_telegram_id=1001,
                    invited_telegram_id=2001,
                    invited_username="profile",
                    invited_display_name="Profile User",
                ),
                ReferralInvite(
                    inviter_telegram_id=2001,
                    invited_telegram_id=3001,
                    invited_username="child",
                    invited_display_name="Child User",
                ),
            ]
        )
        await session.commit()

    profile = await service.get_admin_telegram_user_profile(telegram_id=2001)

    assert profile is not None
    assert profile.user.telegram_id == 2001
    assert profile.referral_code == "SELF2001"
    assert profile.applied_referral_code == "INVITER1001"
    assert profile.invited_count == 1
    assert profile.recent_invited_names == ["Child User"]
    assert len(profile.accesses) == 1
    assert profile.accesses[0].record.username == "oreol-profile"


async def test_sync_all_users_does_not_autoflush_half_built_user(
    session_factory,
) -> None:
    remote_user = make_remote_user(
        user_uuid="77777777-7777-7777-7777-777777777777",
        user_id=7,
        short_uuid="sync-all-user",
        username="oreol-sync-all",
        telegram_id=4001,
    )
    service = SyncService(
        settings=Settings.model_construct(
            bot_admin_ids_raw="",
            sync_subscription_history=False,
        ),
        session_factory=session_factory,
        remnawave_client=_StubRemnawaveClient([remote_user]),
    )

    async with session_factory() as session:
        session.add(
            TelegramUser(
                telegram_id=4001,
                username="owner",
                first_name="Sync",
                last_name="Owner",
                language_code="ru",
            )
        )
        await session.commit()

    total = await service.sync_all_users(batch_size=50)

    assert total == 1

    async with session_factory() as session:
        owner = await session.scalar(
            select(TelegramUser).where(TelegramUser.telegram_id == 4001)
        )
        cached_user = await session.scalar(
            select(RemnawaveUser).where(RemnawaveUser.rw_uuid == str(remote_user.uuid))
        )

    assert owner is not None
    assert cached_user is not None
    assert cached_user.rw_id == 7
    assert cached_user.owner_telegram_user_id == owner.id
    assert cached_user.username == "oreol-sync-all"
