import io
from csv import DictReader
from datetime import datetime, date
from decimal import Decimal
from enum import Enum
from typing import List, Dict

from urllib.parse import urlencode

from ludialudom.errors import SignatureError
from ludialudom.resources.base import BaseResource


class Payment(BaseResource):
    class PaymentState(Enum):
        ACTIVE = 1
        SUSPENDED = 2
        CANCELED = 3
        INVALID_CARD = 4

    """
    Method returns redirect URL for payment
    """
    def create_payment_url(self, payment_id: int, project_code: int, channel: int, amount: Decimal, name: str,
                           surname: str, email: str, start_date: datetime = None, end_date: datetime = None,
                           is_mobile: bool = False) -> str:
        payload = {
            'clientId': self._configuration.client_id,
            'paymentId': payment_id,
            'projectCode': project_code,
            'paymentChannel': channel,
            'amount': amount,
            'name': name,
            'surname': surname,
            'email': email,
            'mobileDevice': 'true' if is_mobile else 'false',
            'sign': self.sign(f"{payment_id}{project_code}{channel}{amount}{name}{surname}{email}")
        }

        if start_date:
            payload['startDate'] = start_date.strftime("%Y-%m-%d %H:%i:%s")

        if end_date:
            payload['endDate'] = end_date.strftime("%Y-%m-%d %H:%i:%s")

        return f"{self._configuration.environment.web_url}/pay?{urlencode(payload)}"

    def change_amount(self, payment_id: int, amount: Decimal) -> bool:
        payload = {
            'paymentId': payment_id,
            'newAmount': amount,
            'sign': self.sign(f"{payment_id}{amount}")
        }

        response = self.requestor.request('POST', '/changeComfortPay', payload=payload)

        if response.get('sign') != self.sign(f"{response.get('result')}{response.get('code')}"):
            raise SignatureError()

        return 'OK' == response.get('result')

    def change_state(self, payment_id: int, state: PaymentState) -> PaymentState:
        payload = {
            'paymentId': payment_id,
            'status': state.value,
            'sign': self.sign(f"{payment_id}{state.value}")
        }

        response = self.requestor.request('POST', '/setComfortPayStatus', payload=payload)
        response_sign = self.sign(f"{response.get('result')}{response.get('code')}{response.get('status')}")

        if response.get('sign') != response_sign:
            raise SignatureError()

        return Payment.PaymentState(response['status'])

    def get_state(self, payment_id: int) -> PaymentState:
        payload = {
            'paymentId': payment_id,
            'sign': self.sign(str(payment_id))
        }

        response = self.requestor.request('POST', '/getComfortPayStatus', payload=payload)
        response_sign = self.sign(f"{response.get('result')}{response.get('code')}{response.get('status')}")

        if response.get('sign') != response_sign:
            raise SignatureError()

        return Payment.PaymentState(response['status'])

    def list(self, project_code: int, date_from: date = None, date_to: date = None) -> List[Dict]:
        payload = {
            'projectCode': project_code,
            'sign': self.sign(f"{project_code}")
        }

        if date_from is not None:
            payload['from'] = date_from.strftime("%Y-%m-%d")

        if date_to is not None:
            payload['to'] = date_to.strftime("%Y-%m-%d")

        response = self.requestor.request('GET', '/GetPayments', query=payload, parse=False)

        reader = DictReader(io.StringIO(response), delimiter=';')

        return list(reader)
