"""Store matching history"""
import os
from datetime import datetime
from schema import Schema, And, Use, Optional
from typing import Protocol
import files
import copy

_FILE = "history.json"

# Warning: Changing any of the below needs proper thought to ensure backwards compatibility
_DEFAULT_DICT = {
    "history": {},
    "matchees": {}
}
_TIME_FORMAT = "%a %b %d %H:%M:%S %Y"
_SCHEMA = Schema(
    {
        Optional("history"): {
            Optional(str): {  # a datetime
                "groups": [
                    {
                        "members": [
                            # The ID of each matchee in the match
                            And(Use(int))
                        ]
                    }
                ]
            }
        },
        Optional("matchees"): {
            Optional(str): {
                Optional("matches"): {
                    # Matchee ID and Datetime pair
                    Optional(str): And(Use(str))
                }
            }
        }
    }
)


class Member(Protocol):
    @property
    def id(self) -> int:
        pass


def ts_to_datetime(ts: str) -> datetime:
    """Convert a ts to datetime using the history format"""
    return datetime.strptime(ts, _TIME_FORMAT)


def validate(dict: dict):
    """Initialise and validate the history"""
    _SCHEMA.validate(dict)


class History():
    def __init__(self, data: dict = _DEFAULT_DICT):
        """Initialise and validate the history"""
        validate(data)
        self.__dict__ = copy.deepcopy(data)

    @property
    def history(self) -> list[dict]:
        return self.__dict__["history"]

    @property
    def matchees(self) -> dict[str, dict]:
        return self.__dict__["matchees"]

    def save(self) -> None:
        """Save out the history"""
        files.save(_FILE, self.__dict__)

    def oldest(self) -> datetime:
        """Grab the oldest timestamp in history"""
        if not self.history:
            return None
        times = (ts_to_datetime(dt) for dt in self.history.keys())
        return sorted(times)[0]

    def log_groups_to_history(self, groups: list[list[Member]], ts: datetime = datetime.now()) -> None:
        """Log the groups"""
        tmp_history = History(self.__dict__)
        ts = datetime.strftime(ts, _TIME_FORMAT)

        # Grab or create the hitory item for this set of groups
        history_item = {}
        tmp_history.history[ts] = history_item
        history_item_groups = []
        history_item["groups"] = history_item_groups

        for group in groups:

            # Add the group data
            history_item_groups.append({
                "members": list(m.id for m in group)
            })

            # Update the matchee data with the matches
            for m in group:
                matchee = tmp_history.matchees.get(str(m.id), {})
                matchee_matches = matchee.get("matches", {})

                for o in (o for o in group if o.id != m.id):
                    matchee_matches[str(o.id)] = ts

                matchee["matches"] = matchee_matches
                tmp_history.matchees[str(m.id)] = matchee

        # Validate before storing the result
        validate(self.__dict__)
        self.__dict__ = tmp_history.__dict__

    def save_groups_to_history(self, groups: list[list[Member]]) -> None:
        """Save out the groups to the history file"""
        self.log_groups_to_history(groups)
        self.save()


def load() -> History:
    """Load the history"""
    return History(files.load(_FILE) if os.path.isfile(_FILE) else _DEFAULT_DICT)