"""
Par contract and scoring function
"""

from __future__ import annotations

__all__ = ["ParList", "par"]

from collections.abc import Iterable, Iterator
from ctypes import pointer
from typing import Union

import endplay._dds as _dds
from endplay.dds.ddtable import DDTable, calc_dd_table
from endplay.types import Contract, Deal, Player, Vul


class ParList(Iterable):
    def __init__(self, data: "_dds.parResultsMaster"):
        self._data = data

    @property
    def score(self) -> int:
        ":return: The score associated with the par contracts"
        return self._data.score

    def __iter__(self) -> Iterator[Contract]:
        ":return: An iterator over all the par contracts"
        for i in range(self._data.number):
            c = self._data.contracts[i]
            if c.seats == 4:
                tmp = _dds.contractType()
                pointer(tmp)[0] = c
                c.seats = 0
                yield Contract(c)
                pointer(tmp)[0] = c
                c.seats = 2
                yield Contract(c)
            elif c.seats == 5:
                tmp = _dds.contractType()
                pointer(tmp)[0] = c
                c.seats = 1
                yield Contract(c)
                pointer(tmp)[0] = c
                c.seats = 3
                yield Contract(c)
            else:
                yield Contract(self._data.contracts[i])

    def __repr__(self) -> str:
        return "<ParList object>"


def par(deal: Union[Deal, DDTable], vul: Union[Vul, int], dealer: Player) -> ParList:
    """
    Calculate the par contract result for the given deal.

    :param deal: The deal to calculate the par result of. If you have already precomputed a DDTable for
            a deal then you speed up the par calculation by passing that instead of the Deal object
    :param vul: The vulnerability of the deal. If you pass an `int` then this is converted from a board
            number into the vulnerability of that board
    :param dealer: The dealer of the board.
    """
    if isinstance(deal, Deal):
        dd_table = calc_dd_table(deal)
    else:
        dd_table = deal
    if not isinstance(vul, Vul):
        vul = Vul.from_board(vul)

    par = _dds.parResultsMaster()
    _dds.DealerParBin(dd_table._data, par, dealer, vul)
    return ParList(par)
