import logging
from typing import Optional

import requests
from django.core.files.base import ContentFile
from videogames.howlongtobeat import lookup_game_from_hltb
from videogames.igdb import lookup_game_from_igdb
from videogames.models import VideoGame, VideoGamePlatform

logger = logging.getLogger(__name__)


def get_or_create_videogame(
    name_or_id: str,
    force_update: bool = False,
) -> Optional[VideoGame]:
    """Look up game by name or ID from HowLongToBeat, then enrich with IGDB"""

    hltb_data = lookup_game_from_hltb(name_or_id)

    if hltb_data:
        game = _create_update_from_dict(hltb_data, force_update)
    else:
        igdb_data = lookup_game_from_igdb(name_or_id)
        if igdb_data:
            game = _create_update_from_dict(igdb_data, force_update)
        else:
            return None

    if game:
        game.fix_metadata()
    return game


def _create_update_from_dict(
    game_dict: dict, force_update: bool = False
) -> Optional[VideoGame]:

    platform_ids = []
    if "platforms" in game_dict.keys():
        platforms = game_dict.get("platforms", [])
        if platforms:
            for platform in platforms:
                p, _created = VideoGamePlatform.objects.get_or_create(name=platform)
                platform_ids.append(p.id)
        game_dict.pop("platforms")

    cover_url = game_dict.pop("cover_url")

    screenshot_url = ""
    if "screenshot_url" in game_dict.keys():
        screenshot_url = game_dict.pop("screenshot_url")

    genres = []
    if "genres" in game_dict.keys():
        genres = game_dict.pop("genres")

    title = game_dict.get("title")
    if not title:
        return None

    hltb_id = game_dict.get("hltb_id")
    igdb_id = game_dict.get("igdb_id")
    if hltb_id:
        game, game_created = VideoGame.objects.get_or_create(
            hltb_id=hltb_id,
            title=title,
        )
    elif igdb_id:
        game, game_created = VideoGame.objects.get_or_create(
            igdb_id=igdb_id,
            title=title,
        )
    else:
        game, game_created = VideoGame.objects.get_or_create(title=title)

    if game_created or force_update:
        VideoGame.objects.filter(pk=game.id).update(**game_dict)
        game.refresh_from_db()

        if platform_ids:
            game.platforms.add(*platform_ids)

        if genres:
            game.genre.add(*genres)

        if screenshot_url:
            r = requests.get(screenshot_url)
            if r.status_code == 200:
                fname = f"{game.title}_{game.uuid}.jpg"
                game.screenshot.save(fname, ContentFile(r.content), save=True)

        if cover_url:
            headers = {"User-Agent": "Vrobbler 0.11.12"}
            r = requests.get(cover_url, headers=headers)
            logger.debug(r.status_code)
            if r.status_code == 200:
                fname = f"{game.title}_cover_{game.uuid}.jpg"
                game.hltb_cover.save(fname, ContentFile(r.content), save=True)
                logger.debug("Loaded cover image from HLtB")

        tag = "hltb-enriched" if hltb_id else "igdb-enriched"
        if tag not in game.tags.names():
            game.tags.add(tag)
            logger.info(f"Game {game} tagged {tag}")

    return game


def load_game_data_from_hltb(
    game_id: int, expected_title: str = ""
) -> Optional[VideoGame]:
    """Look up HLtB data for an existing game and apply it"""
    game = VideoGame.objects.filter(id=game_id).first()
    if not game:
        logger.warn(f"Video game with ID {game_id} not found")
        return

    logger.info(f"Looking up HLtB data for {game}")
    hltb_data = lookup_game_from_hltb(game.title, search_by_title=True)
    if not hltb_data:
        logger.warn(f"No HLtB data found for {game}")
        return

    update_fields = []

    hltb_title = hltb_data.get("title", "")
    if hltb_title and hltb_title != game.title:
        game.title = hltb_title
        update_fields.append("title")
        logger.info(f"Game {game.id} title updated to {hltb_title!r}")

    if hltb_data.get("hltb_id") and (game.hltb_id is None):
        game.hltb_id = hltb_data["hltb_id"]
        update_fields.append("hltb_id")

    if hltb_data.get("release_year") and (game.release_year is None):
        game.release_year = hltb_data["release_year"]
        update_fields.append("release_year")

    if hltb_data.get("main_story_time") and (game.main_story_time is None):
        game.main_story_time = hltb_data["main_story_time"]
        update_fields.append("main_story_time")

    if hltb_data.get("main_extra_time") and (game.main_extra_time is None):
        game.main_extra_time = hltb_data["main_extra_time"]
        update_fields.append("main_extra_time")

    if hltb_data.get("completionist_time") and (game.completionist_time is None):
        game.completionist_time = hltb_data["completionist_time"]
        update_fields.append("completionist_time")

    if hltb_data.get("hltb_score") is not None and (game.hltb_score is None):
        game.hltb_score = hltb_data["hltb_score"]
        update_fields.append("hltb_score")

    if update_fields:
        game.save(update_fields=update_fields)

    platforms = hltb_data.get("platforms", [])
    if platforms:
        for name in platforms:
            p, _ = VideoGamePlatform.objects.get_or_create(name=name)
            game.platforms.add(p)

    cover_url = hltb_data.get("cover_url")
    if cover_url:
        headers = {"User-Agent": "Vrobbler 0.11.12"}
        r = requests.get(cover_url, headers=headers)
        if r.status_code == 200:
            fname = f"{game.title}_cover_{game.uuid}.jpg"
            game.hltb_cover.save(fname, ContentFile(r.content), save=True)

    if "hltb-enriched" not in game.tags.names():
        game.tags.add("hltb-enriched")
        logger.info(f"Game {game} tagged hltb-enriched")

    return game


def load_game_data_from_igdb(
    game_id: int, igdb_id: str = "", expected_title: str = ""
) -> Optional[VideoGame]:
    """Look up game, if it doesn't exist, lookup data from igdb"""
    game = VideoGame.objects.filter(id=game_id).first()
    if not game:
        logger.warn(f"Video game with ID {game_id} not found")
        return

    if not game.igdb_id and not igdb_id:
        logger.warn(f"Video game has no IGDB ID")
        return

    igdb_id = game.igdb_id or igdb_id

    logger.info(f"Looking up video game {igdb_id}")
    game_dict = lookup_game_from_igdb(igdb_id)

    if not game_dict:
        logger.warn(f"No game data found on IGDB for ID {igdb_id}")
        return

    igdb_title = game_dict.get("title", "")
    igdb_title_clean = igdb_title.split(" (")[0].strip() if " (" in igdb_title else igdb_title
    expected = expected_title or game.title
    if igdb_title_clean.lower() != expected.lower():
        logger.info(
            f"IGDB title {igdb_title!r} doesn't match expected {expected!r} for {game} — re-searching…"
        )
        from videogames.igdb import lookup_game_id_from_gdb

        new_id = lookup_game_id_from_gdb(expected)
        if new_id:
            new_data = lookup_game_from_igdb(str(new_id))
            if new_data:
                new_title = new_data.get("title", "")
                new_title_clean = new_title.split(" (")[0].strip() if " (" in new_title else new_title
                if new_title_clean.lower() == expected.lower():
                    game_dict = new_data
                    igdb_id = int(new_id)
                    if game.igdb_id != igdb_id:
                        game.igdb_id = igdb_id
                        game.save(update_fields=["igdb_id"])
                        logger.info(f"Game {game} IGDB ID updated to {igdb_id}")

        igdb_title = game_dict.get("title", "")
        igdb_title_clean = igdb_title.split(" (")[0].strip() if " (" in igdb_title else igdb_title
        if igdb_title_clean.lower() != expected.lower():
            if "igdb-mismatch" not in game.tags.names():
                game.tags.add("igdb-mismatch")
                logger.info(
                    f"Game {game} tagged igdb-mismatch (IGDB: {igdb_title!r} vs expected: {expected!r})"
                )
            return

    screenshot_url = game_dict.pop("screenshot_url")
    cover_url = game_dict.pop("cover_url")
    genres = game_dict.pop("genres")
    platforms = game_dict.pop("platforms", [])

    VideoGame.objects.filter(pk=game.id).update(**game_dict)
    game.refresh_from_db()

    game.genre.add(*genres)

    if platforms:
        for name in platforms:
            p, _ = VideoGamePlatform.objects.get_or_create(name=name)
            game.platforms.add(p)

    if screenshot_url:
        r = requests.get(screenshot_url)
        if r.status_code == 200:
            fname = f"{game.title}_{game.uuid}.jpg"
            game.screenshot.save(fname, ContentFile(r.content), save=True)

    if cover_url:
        r = requests.get(cover_url)
        if r.status_code == 200:
            fname = f"{game.title}_{game.uuid}.jpg"
            game.cover.save(fname, ContentFile(r.content), save=True)

    if "igdb-enriched" not in game.tags.names():
        game.tags.add("igdb-enriched")
        logger.info(f"Game {game} tagged igdb-enriched")

    return game
