import typing

from apps.authentication.services.service import get_bank_info
from apps.pos_device.models import Device, StakeHolders
from apps.product.models import (
    Quota,
    QuotaDistribution,
    Organization, OrganizationQuotaStats
)


def pos_organizations_sharing_information(
        device: Device,
        quota: Quota = None,
        quota_stat: OrganizationQuotaStats = None,
        distribution: QuotaDistribution = None,
        owner_org: Organization = None
) -> typing.Any:
    """
    pos sharing organizations' information,
    device have multiple organizations (sub_accounts) for sharing money
    """
    stake_holders_qs = (
        device.stake_holders
        .select_related('broker', 'organization')
        .prefetch_related('organization__bank_information')
    )

    broker_values_qs = quota.broker_values.all()

    if quota_stat and quota_stat.broker_values.exists():
        broker_values_qs = broker_values_qs.filter(org_quota_stat=quota_stat)

    broker_value_map = {
        bv.broker_id: bv.value
        for bv in broker_values_qs
    }

    if owner_org.type.key == 'AGC':
        agc_stake_holder = (
            owner_org.pos_stake_holders
            .filter(holders_share_amount__org_quota_stat=quota_stat)
            .select_related('device')
            .first()
        )

        if agc_stake_holder:
            stake_holders_qs = (
                agc_stake_holder.device.stake_holders
                .select_related('broker', 'organization')
                .prefetch_related('organization__bank_information')
            )

    sharing_information_list = []

    for item in stake_holders_qs:
        if not item.broker:
            continue

        sharing_information_list.append({
            "organization_name": item.organization.name,
            "bank_account": get_bank_info(item.organization, device=device),
            "broker": item.broker.name,
            "amount": broker_value_map.get(item.broker_id),
            "agency": False,
            "default_account": item.default,
        })

    # if device owner is an agency organization
    if owner_org.type.key == 'AGC':
        sharing_information_list_agency = agency_organization_pos_info(
            agency=owner_org,
            pos_sharing_list=sharing_information_list,
            device=device,
            distribution=distribution,
            quota_stat=quota_stat
        )

        if sharing_information_list_agency:
            return sharing_information_list_agency

    return sharing_information_list


def agency_organization_pos_info(
        agency: Organization = None,
        pos_sharing_list: list = None,
        device: Device = None,
        distribution: QuotaDistribution = None,
        quota_stat: OrganizationQuotaStats = None
) -> typing.Any:
    """
    if pos org owner is an agency, calculate share amount of agency
    and share amount of parent organization
    """

    # get agency share amount
    agc_stake_holder = (
        agency.pos_stake_holders
        .filter(holders_share_amount__org_quota_stat=quota_stat)
        .select_related('device')
    )

    agc_share_amount = agc_stake_holder.first().holders_share_amount.filter(
        org_quota_stat=quota_stat
    ) if agc_stake_holder.exists() else None

    agc_share_amount = agc_share_amount.first().share_amount if agc_share_amount else None

    if agc_share_amount:
        # calculate agency parent share amount
        agc_parent_amount = next((item for item in pos_sharing_list if item.get('default_account')), None)
        if agc_parent_amount and agc_share_amount:
            agc_parent_amount['amount'] = agc_parent_amount['amount'] - agc_share_amount

            pos_sharing_list.append({
                "organization_name": agency.name,
                "bank_account": get_bank_info(org=agency, device=device),
                "amount": agc_share_amount,
                "agency": True,
                "default_account": True
            })
            return pos_sharing_list
        return None
    return None


def get_organization_by_stake_holder(id: int = None, stake_holder: StakeHolders = None) -> typing.Any:
    """ get organization object by stake holder """

    if id:
        stake_holder = StakeHolders.objects.get(id=id)
        organization = get_organization_by_stake_holder(stake_holder=stake_holder)
        return organization
    organization = stake_holder.assignment.client.organization
    return organization
