import uuid
from datetime import datetime, timedelta
from typing import Any, ClassVar, Dict, List, Optional, Union

from pydantic import Field, validator

from glQiwiApi.core.abc.api_method import Request, RuntimeValue
from glQiwiApi.qiwi.base import QiwiAPIMethod
from glQiwiApi.qiwi.clients.p2p.types import Bill, Customer
from glQiwiApi.utils.date_conversion import datetime_to_iso8601_with_moscow_timezone


def get_default_bill_life_time() -> datetime:
    return datetime.now() + timedelta(days=2)


class CreateP2PBill(QiwiAPIMethod[Bill]):
    http_method: ClassVar[str] = 'PUT'
    url: ClassVar[str] = 'https://api.qiwi.com/partner/bill/v1/bills/{bill_id}'

    json_payload_schema: ClassVar[Dict[str, Any]] = {
        'amount': {'currency': 'RUB', 'value': RuntimeValue()},
        'expirationDateTime': RuntimeValue(default_factory=get_default_bill_life_time),
        'comment': RuntimeValue(mandatory=False),
        'customFields': {
            'paySourcesFilter': RuntimeValue(default=['qw', 'card']),
            'themeCode': RuntimeValue(default='Yvan-YKaSh'),
        },
        'customer': RuntimeValue(mandatory=False),
    }

    bill_id: Optional[str] = Field(None, path_runtime_value=True)
    expire_at: Optional[datetime] = Field(
        scheme_path='expirationDateTime',
    )
    amount: float = Field(..., scheme_path='amount.value')
    comment: Optional[str] = Field(None, scheme_path='comment')
    theme_code: Optional[str] = Field(None, scheme_path='customFields.themeCode')
    pay_source_filter: Optional[List[str]] = Field(
        None, scheme_path='customFields.paySourcesFilter'
    )
    customer: Optional[Customer] = Field(None, schema_path='customer')

    @validator('bill_id')
    def set_bill_id_if_it_is_none(cls, v: Optional[str]) -> str:
        return v or str(uuid.uuid4())

    def build_request(self, **url_format_kw: Any) -> 'Request':
        request = super().build_request(**url_format_kw)
        expire_at = request.json_payload['expirationDateTime']  # type: ignore
        request.json_payload['expirationDateTime'] = datetime_to_iso8601_with_moscow_timezone(
            expire_at
        )
        pay_source_filter = request.json_payload['customFields']['paySourcesFilter']
        if isinstance(pay_source_filter, list):
            request.json_payload['customFields']['paySourcesFilter'] = ' '.join(
                pay_source_filter
            ).replace(' ', ',')
        return request
