import logging
from typing import Literal

from github import Github
from github.PullRequestReview import PullRequestReview
from pydantic import BaseModel, SecretStr
from pydantic_settings import BaseSettings


class LabelSettings(BaseModel):
    await_label: str | None = None
    number: int


default_config = {"approved-2": LabelSettings(await_label="awaiting-review", number=2)}


class Settings(BaseSettings):
    github_repository: str
    token: SecretStr
    debug: bool | None = False
    config: dict[str, LabelSettings] | Literal[""] = default_config


settings = Settings()
if settings.debug:
    logging.basicConfig(level=logging.DEBUG)
else:
    logging.basicConfig(level=logging.INFO)
logging.debug(f"Using config: {settings.json()}")
g = Github(settings.token.get_secret_value())
repo = g.get_repo(settings.github_repository)
for pr in repo.get_pulls(state="open"):
    logging.info(f"Checking PR: #{pr.number}")
    pr_labels = list(pr.get_labels())
    pr_label_by_name = {label.name: label for label in pr_labels}
    reviews = list(pr.get_reviews())
    review_by_user: dict[str, PullRequestReview] = {}
    for review in reviews:
        if review.user.login in review_by_user:
            stored_review = review_by_user[review.user.login]
            if review.submitted_at >= stored_review.submitted_at:
                review_by_user[review.user.login] = review
        else:
            review_by_user[review.user.login] = review
    approved_reviews = [
        review for review in review_by_user.values() if review.state == "APPROVED"
    ]
    config = settings.config or default_config
    for approved_label, conf in config.items():
        logging.debug(f"Processing config: {conf.json()}")
        if conf.await_label is None or (conf.await_label in pr_label_by_name):
            logging.debug(f"Processable PR: {pr.number}")
            if len(approved_reviews) >= conf.number:
                logging.info(f"Adding label to PR: {pr.number}")
                pr.add_to_labels(approved_label)
                if conf.await_label:
                    logging.info(f"Removing label from PR: {pr.number}")
                    pr.remove_from_labels(conf.await_label)
logging.info("Finished")
