import argparse
import json
import logging
from datetime import datetime
from pathlib import Path
from typing import Iterable

from unwind import db, models, types

log = logging.getLogger(__name__)

name = "import-wikidata-oscars"
help = "Import Academy awards information from a Wikidata dump."

# To generate the JSON file, run the following query
# at https://query.wikidata.org/ and export as (simpel) JSON:
"""
SELECT ?awardLabel ?filmLabel ?imdbId ?time WHERE {
  ?award wdt:P31 wd:Q19020.
  ?film wdt:P31 wd:Q11424;
    p:P166 ?awardStat.
  ?awardStat ps:P166 ?award.
  OPTIONAL {
    ?awardStat pq:P805 ?awardEdition.
    ?awardEdition wdt:P585 ?time.
    ?film wdt:P345 ?imdbId.
  }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
ORDER BY DESC (?time)
"""


def add_args(cmd: argparse.ArgumentParser) -> None:
    cmd.add_argument("--json-file", required=True, type=Path)


def load_awards(json_file: Path) -> Iterable[tuple[types.ImdbMovieId, models.Award]]:
    with json_file.open() as fd:
        data = json.load(fd)

    name_prefix = "Academy Award for "
    special_names = {
        "Special Achievement Academy Award": "Special Achievement",
        "Academy Honorary Award": "Honorary",
    }
    for item in data:
        name = item["awardLabel"]
        if name in special_names:
            name = special_names[name]
        elif name.startswith(name_prefix):
            name = name.removeprefix(name_prefix)
        else:
            raise ValueError(f"Award name is unexpected: {name!a}")
        # award = models.Award(category="oscars",details={"name":name},created=created)
        award = models.Award(category="oscars")
        # award._details = {"name": name}
        award.name = name
        if (datestr := item.get("time")) is not None:
            award.created = datetime.fromisoformat(datestr)

        if "imdbId" not in item:
            log.warning("⚠️ IMDb ID missing for movie: %a", item["filmLabel"])
        else:
            yield item["imdbId"], award


async def remove_all_oscars(conn: db.Connection) -> None:
    stmt = models.awards.delete().where(models.awards.c.category == "oscars")
    await conn.execute(stmt)


async def main(args: argparse.Namespace) -> None:
    await db.open_connection_pool()

    json_file: Path = args.json_file

    awards: dict[types.ImdbMovieId, list[models.Award]] = {}
    for imdb_id, award in load_awards(json_file):
        awards.setdefault(imdb_id, []).append(award)
    async with db.new_connection() as conn:
        imdb_ids = list(awards)
        available = await db.get_movie_ids(conn, imdb_ids)
        if missing := set(imdb_ids).difference(available):
            log.warning(
                "⚠️ File (%a) contained %i unknown movies: %a",
                str(json_file),
                len(missing),
                missing,
            )

    async with db.transaction() as conn:
        await remove_all_oscars(conn)

        for imdb_id, unwind_id in available.items():
            for award in awards[imdb_id]:
                award.movie_id = unwind_id
                await db.add(conn, award)

    log.info(f"✨ Imported {len(available)} oscars.")

    await db.close_connection_pool()
