# Copyright ©, 2022-present, Lightspark Group, Inc. - All Rights Reserved

from dataclasses import dataclass
from datetime import datetime
from typing import Any, Mapping, Optional

from lightspark.objects.WithdrawalMode import WithdrawalMode
from lightspark.objects.WithdrawalRequestStatus import WithdrawalRequestStatus
from lightspark.requests.requester import Requester
from lightspark.utils.enums import parse_enum

from .CurrencyAmount import CurrencyAmount
from .CurrencyAmount import from_json as CurrencyAmount_from_json
from .Entity import Entity
from .WithdrawalMode import WithdrawalMode
from .WithdrawalRequestStatus import WithdrawalRequestStatus
from .WithdrawalRequestToChannelClosingTransactionsConnection import (
    WithdrawalRequestToChannelClosingTransactionsConnection,
)
from .WithdrawalRequestToChannelClosingTransactionsConnection import (
    from_json as WithdrawalRequestToChannelClosingTransactionsConnection_from_json,
)
from .WithdrawalRequestToChannelOpeningTransactionsConnection import (
    WithdrawalRequestToChannelOpeningTransactionsConnection,
)
from .WithdrawalRequestToChannelOpeningTransactionsConnection import (
    from_json as WithdrawalRequestToChannelOpeningTransactionsConnection_from_json,
)


@dataclass
class WithdrawalRequest(Entity):
    requester: Requester

    id: str
    """The unique identifier of this entity across all Lightspark systems. Should be treated as an opaque string."""

    created_at: datetime
    """The date and time when the entity was first created."""

    updated_at: datetime
    """The date and time when the entity was last updated."""

    amount: CurrencyAmount
    """The amount of money that should be withdrawn in this request."""

    estimated_amount: Optional[CurrencyAmount]
    """If the requested amount is `-1` (i.e. everything), this field may contain an estimate of the amount for the withdrawal."""

    bitcoin_address: str
    """The bitcoin address where the funds should be sent."""

    withdrawal_mode: WithdrawalMode
    """The strategy that should be used to withdraw the funds from the account."""

    status: WithdrawalRequestStatus
    """The current status of this withdrawal request."""

    completed_at: Optional[datetime]
    """The time at which this request was completed."""

    withdrawal_id: Optional[str]
    """The withdrawal transaction that has been generated by this request."""
    typename: str

    def get_channel_closing_transactions(
        self, first: Optional[int] = None
    ) -> WithdrawalRequestToChannelClosingTransactionsConnection:
        json = self.requester.execute_graphql(
            """
query FetchWithdrawalRequestToChannelClosingTransactionsConnection($entity_id: ID!, $first: Int) {
    entity(id: $entity_id) {
        ... on WithdrawalRequest {
            channel_closing_transactions(, first: $first) {
                __typename
                withdrawal_request_to_channel_closing_transactions_connection_page_info: page_info {
                    __typename
                    page_info_has_next_page: has_next_page
                    page_info_has_previous_page: has_previous_page
                    page_info_start_cursor: start_cursor
                    page_info_end_cursor: end_cursor
                }
                withdrawal_request_to_channel_closing_transactions_connection_count: count
                withdrawal_request_to_channel_closing_transactions_connection_entities: entities {
                    __typename
                    channel_closing_transaction_id: id
                    channel_closing_transaction_created_at: created_at
                    channel_closing_transaction_updated_at: updated_at
                    channel_closing_transaction_status: status
                    channel_closing_transaction_resolved_at: resolved_at
                    channel_closing_transaction_amount: amount {
                        __typename
                        currency_amount_original_value: original_value
                        currency_amount_original_unit: original_unit
                        currency_amount_preferred_currency_unit: preferred_currency_unit
                        currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
                        currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
                    }
                    channel_closing_transaction_transaction_hash: transaction_hash
                    channel_closing_transaction_fees: fees {
                        __typename
                        currency_amount_original_value: original_value
                        currency_amount_original_unit: original_unit
                        currency_amount_preferred_currency_unit: preferred_currency_unit
                        currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
                        currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
                    }
                    channel_closing_transaction_block_hash: block_hash
                    channel_closing_transaction_block_height: block_height
                    channel_closing_transaction_destination_addresses: destination_addresses
                    channel_closing_transaction_num_confirmations: num_confirmations
                    channel_closing_transaction_channel: channel {
                        id
                    }
                }
            }
        }
    }
}
            """,
            {"entity_id": self.id, "first": first},
        )
        connection = json["entity"]["channel_closing_transactions"]
        return WithdrawalRequestToChannelClosingTransactionsConnection_from_json(
            self.requester, connection
        )

    def get_channel_opening_transactions(
        self, first: Optional[int] = None
    ) -> WithdrawalRequestToChannelOpeningTransactionsConnection:
        json = self.requester.execute_graphql(
            """
query FetchWithdrawalRequestToChannelOpeningTransactionsConnection($entity_id: ID!, $first: Int) {
    entity(id: $entity_id) {
        ... on WithdrawalRequest {
            channel_opening_transactions(, first: $first) {
                __typename
                withdrawal_request_to_channel_opening_transactions_connection_page_info: page_info {
                    __typename
                    page_info_has_next_page: has_next_page
                    page_info_has_previous_page: has_previous_page
                    page_info_start_cursor: start_cursor
                    page_info_end_cursor: end_cursor
                }
                withdrawal_request_to_channel_opening_transactions_connection_count: count
                withdrawal_request_to_channel_opening_transactions_connection_entities: entities {
                    __typename
                    channel_opening_transaction_id: id
                    channel_opening_transaction_created_at: created_at
                    channel_opening_transaction_updated_at: updated_at
                    channel_opening_transaction_status: status
                    channel_opening_transaction_resolved_at: resolved_at
                    channel_opening_transaction_amount: amount {
                        __typename
                        currency_amount_original_value: original_value
                        currency_amount_original_unit: original_unit
                        currency_amount_preferred_currency_unit: preferred_currency_unit
                        currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
                        currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
                    }
                    channel_opening_transaction_transaction_hash: transaction_hash
                    channel_opening_transaction_fees: fees {
                        __typename
                        currency_amount_original_value: original_value
                        currency_amount_original_unit: original_unit
                        currency_amount_preferred_currency_unit: preferred_currency_unit
                        currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
                        currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
                    }
                    channel_opening_transaction_block_hash: block_hash
                    channel_opening_transaction_block_height: block_height
                    channel_opening_transaction_destination_addresses: destination_addresses
                    channel_opening_transaction_num_confirmations: num_confirmations
                    channel_opening_transaction_channel: channel {
                        id
                    }
                }
            }
        }
    }
}
            """,
            {"entity_id": self.id, "first": first},
        )
        connection = json["entity"]["channel_opening_transactions"]
        return WithdrawalRequestToChannelOpeningTransactionsConnection_from_json(
            self.requester, connection
        )


FRAGMENT = """
fragment WithdrawalRequestFragment on WithdrawalRequest {
    __typename
    withdrawal_request_id: id
    withdrawal_request_created_at: created_at
    withdrawal_request_updated_at: updated_at
    withdrawal_request_amount: amount {
        __typename
        currency_amount_original_value: original_value
        currency_amount_original_unit: original_unit
        currency_amount_preferred_currency_unit: preferred_currency_unit
        currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
        currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
    }
    withdrawal_request_estimated_amount: estimated_amount {
        __typename
        currency_amount_original_value: original_value
        currency_amount_original_unit: original_unit
        currency_amount_preferred_currency_unit: preferred_currency_unit
        currency_amount_preferred_currency_value_rounded: preferred_currency_value_rounded
        currency_amount_preferred_currency_value_approx: preferred_currency_value_approx
    }
    withdrawal_request_bitcoin_address: bitcoin_address
    withdrawal_request_withdrawal_mode: withdrawal_mode
    withdrawal_request_status: status
    withdrawal_request_completed_at: completed_at
    withdrawal_request_withdrawal: withdrawal {
        id
    }
}
"""


def from_json(requester: Requester, obj: Mapping[str, Any]) -> WithdrawalRequest:
    return WithdrawalRequest(
        requester=requester,
        typename="WithdrawalRequest",
        id=obj["withdrawal_request_id"],
        created_at=obj["withdrawal_request_created_at"],
        updated_at=obj["withdrawal_request_updated_at"],
        amount=CurrencyAmount_from_json(requester, obj["withdrawal_request_amount"]),
        estimated_amount=CurrencyAmount_from_json(
            requester, obj["withdrawal_request_estimated_amount"]
        )
        if obj["withdrawal_request_estimated_amount"]
        else None,
        bitcoin_address=obj["withdrawal_request_bitcoin_address"],
        withdrawal_mode=parse_enum(
            WithdrawalMode, obj["withdrawal_request_withdrawal_mode"]
        ),
        status=parse_enum(WithdrawalRequestStatus, obj["withdrawal_request_status"]),
        completed_at=obj["withdrawal_request_completed_at"],
        withdrawal_id=obj["withdrawal_request_withdrawal"]["id"]
        if obj["withdrawal_request_withdrawal"]
        else None,
    )
