"""Тесты Pal24Service и вспомогательных функций."""

from __future__ import annotations

import sys
from datetime import UTC, datetime, timedelta
from decimal import Decimal
from pathlib import Path
from typing import Any

import pytest


ROOT_DIR = Path(__file__).resolve().parents[2]
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

from app.config import settings
from app.external.pal24_client import Pal24APIError, Pal24Client
from app.services.pal24_service import Pal24Service


class StubPal24Client:
    def __init__(self, configured: bool = True, response: dict[str, Any] | None = None) -> None:
        self.is_configured = configured
        self.response = response or {
            'success': True,
            'bill_id': 'BILL42',
            'status': 'NEW',
            'transfer_url': 'https://pal24/sbp',
            'link_url': 'https://pal24/card',
            'currency': 'RUB',
        }
        self.calls: list[dict[str, Any]] = []

    async def create_bill(self, **kwargs: Any) -> dict[str, Any]:
        self.calls.append(kwargs)
        return self.response

    async def get_bill_status(self, bill_id: str) -> dict[str, Any]:
        return {'id': bill_id, 'status': 'NEW'}

    async def get_payment_status(self, payment_id: str) -> dict[str, Any]:
        return {'id': payment_id, 'status': 'SUCCESS'}

    async def get_bill_payments(self, bill_id: str) -> dict[str, Any]:
        return {'id': bill_id, 'payments': [{'id': 'PAY-1'}]}


def _enable_pal24(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(type(settings), 'is_pal24_enabled', lambda self: True, raising=False)
    monkeypatch.setattr(settings, 'PAL24_SHOP_ID', 'shop42', raising=False)
    monkeypatch.setattr(settings, 'PAL24_SIGNATURE_TOKEN', 'sigsecret', raising=False)


@pytest.fixture
def anyio_backend() -> str:
    return 'asyncio'


@pytest.mark.anyio('asyncio')
async def test_create_bill_success(monkeypatch: pytest.MonkeyPatch) -> None:
    _enable_pal24(monkeypatch)
    client = StubPal24Client()
    service = Pal24Service(client)

    monkeypatch.setattr(Pal24Client, 'normalize_amount', staticmethod(lambda amount: Decimal('500.00')), raising=False)

    result = await service.create_bill(
        amount_kopeks=50000,
        user_id=7,
        order_id='order-7',
        description='Пополнение',
        ttl_seconds=600,
        custom_payload={'extra': 'value'},
        payer_email='user@example.com',
        payment_method='BANK_CARD',
    )

    assert result['bill_id'] == 'BILL42'
    assert client.calls and client.calls[0]['amount'] == Decimal('500.00')
    assert client.calls[0]['shop_id'] == 'shop42'
    assert client.calls[0]['description'] == 'Пополнение'
    assert client.calls[0]['custom'] == {'extra': 'value'}
    assert client.calls[0]['payment_method'] == 'BANK_CARD'


@pytest.mark.anyio('asyncio')
async def test_create_bill_requires_configuration(monkeypatch: pytest.MonkeyPatch) -> None:
    _enable_pal24(monkeypatch)
    client = StubPal24Client(configured=False)
    service = Pal24Service(client)

    with pytest.raises(Pal24APIError):
        await service.create_bill(
            amount_kopeks=1000,
            user_id=1,
            order_id='order',
            description='desc',
        )


@pytest.mark.anyio('asyncio')
async def test_get_bill_payments(monkeypatch: pytest.MonkeyPatch) -> None:
    _enable_pal24(monkeypatch)
    client = StubPal24Client()
    service = Pal24Service(client)

    result = await service.get_bill_payments('BILL42')

    assert result == {'id': 'BILL42', 'payments': [{'id': 'PAY-1'}]}


def test_parse_callback_success(monkeypatch: pytest.MonkeyPatch) -> None:
    _enable_pal24(monkeypatch)
    sig = Pal24Client.calculate_signature('100.00', 'INV1', api_token='sigsecret')
    payload = {
        'InvId': 'INV1',
        'OutSum': '100.00',
        'Status': 'SUCCESS',
        'SignatureValue': sig,
    }
    result = Pal24Service.parse_callback(payload)
    assert result['InvId'] == 'INV1'


def test_parse_callback_missing_fields(monkeypatch: pytest.MonkeyPatch) -> None:
    _enable_pal24(monkeypatch)
    with pytest.raises(Pal24APIError):
        Pal24Service.parse_callback({'InvId': '1'})


def test_convert_to_kopeks_and_expiration() -> None:
    assert Pal24Service.convert_to_kopeks('10.50') == 1050
    expiration = Pal24Service.get_expiration(60)
    assert isinstance(expiration, datetime)
    assert expiration - datetime.now(UTC) <= timedelta(seconds=61)
