#!/usr/bin/env python3
"""Generate an HTML playtime report from a Lutris SQLite database."""

####################################################################################################
# Copyright (C) 2026 by WallyHackenslacker wallyhackenslacker@noreply.git.hackenslacker.space      #
#                                                                                                  #
# Permission to use, copy, modify, and/or distribute this software for any purpose with or without #
# fee is hereby granted.                                                                           #
#                                                                                                  #
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS     #
# SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE  #
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES      #
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,        #
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE #
# OF THIS SOFTWARE.                                                                                #
####################################################################################################

import argparse
import base64
import json
import sqlite3
from pathlib import Path

from styles import get_theme_css, get_theme_config

# Directory where this script is located (for finding template.html)
SCRIPT_DIR = Path(__file__).parent

# Modern styles that use the unified template
MODERN_STYLES = ["brutalism", "glassmorphism", "neumorphism", "material", "flat", "synthwave", "vaporwave", "terminal", "highcontrast"]


def load_template(template_file: str) -> str:
    """Load the HTML template from the specified file."""
    template_path = SCRIPT_DIR / template_file
    return template_path.read_text(encoding="utf-8")


def load_script(script_file: str) -> str:
    """Load the JS script from the specified file."""
    script_path = SCRIPT_DIR / script_file
    return script_path.read_text(encoding="utf-8")


def load_asset_as_base64(path: Path, mime_type: str) -> str:
    """Load a file and return it as a base64 data URL."""
    if path.exists():
        with open(path, "rb") as f:
            data = base64.b64encode(f.read()).decode("utf-8")
            return f"data:{mime_type};base64,{data}"
    return ""


def get_all_games(db_path: str) -> tuple[list[dict], int]:
    """Query the database and return all games with playtime and categories, plus total library count."""
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    cursor.execute("SELECT COUNT(*) FROM games")
    total_library = cursor.fetchone()[0]

    cursor.execute("""
        SELECT id, name, playtime, COALESCE(service, 'local') as service, COALESCE(runner, 'unknown') as runner
        FROM games
        WHERE playtime > 0
        ORDER BY playtime DESC
    """)
    games_rows = cursor.fetchall()

    cursor.execute("""
        SELECT gc.game_id, c.name
        FROM games_categories gc
        JOIN categories c ON gc.category_id = c.id
    """)
    categories_rows = cursor.fetchall()
    conn.close()

    game_categories = {}
    for game_id, category in categories_rows:
        if game_id not in game_categories:
            game_categories[game_id] = []
        game_categories[game_id].append(category)

    games = [
        {
            "name": row[1],
            "playtime": row[2],
            "service": row[3],
            "runner": row[4],
            "categories": game_categories.get(row[0], [])
        }
        for row in games_rows
    ]
    return games, total_library


def generate_report(db_path: str, output_path: str, top_n: int, assets_dir: str, template_file: str, bg_image_path: str = None, style: str = None) -> None:
    """Generate the HTML report."""
    all_games, total_library = get_all_games(db_path)

    if not all_games:
        print("No games with playtime found in the database.")
        return

    total_playtime = sum(g["playtime"] for g in all_games)
    total_games = len(all_games)

    assets_path = Path(assets_dir)

    # Load background image (custom or default stripes)
    if bg_image_path and Path(bg_image_path).exists():
        background_image = load_asset_as_base64(Path(bg_image_path), "image/png")
        background_image_custom = f"url('{background_image}')"
    else:
        background_image = load_asset_as_base64(assets_path / "Others" / "stripes.png", "image/png")
        background_image_custom = "none"  # For templates that prefer no default background

    # Check if using modern unified template
    if style and style in MODERN_STYLES:
        html = load_template("templates/modern.html")

        # Inject theme CSS and config
        theme_css = get_theme_css(style)
        theme_config = get_theme_config(style)

        # Inject javascript
        javascript = load_script('templates/script.js')
        javascript = javascript.replace("__ALL_GAMES__", json.dumps(all_games))
        javascript = javascript.replace("__TOP_N__", str(top_n))
        javascript = javascript.replace("__THEME_CONFIG__", theme_config)

        html = html.replace("__THEME_CSS__", theme_css)
        html = html.replace("__SCRIPT__", javascript)
        html = html.replace("__TOTAL_LIBRARY__", str(total_library))
        html = html.replace("__BACKGROUND_IMAGE__", background_image)
        html = html.replace("__BACKGROUND_IMAGE_CUSTOM__", background_image_custom)
    else:
        # Legacy template handling (platinum and others)
        # Load fonts
        font_charcoal = load_asset_as_base64(assets_path / "Charcoal.ttf", "font/truetype")
        font_monaco = load_asset_as_base64(assets_path / "MONACO.TTF", "font/truetype")

        # Load images
        titlebar_bg = load_asset_as_base64(assets_path / "Windows" / "title-1-active.png", "image/png")
        title_stripes = load_asset_as_base64(assets_path / "Windows" / "title-1-active.png", "image/png")
        close_btn = load_asset_as_base64(assets_path / "Windows" / "close-active.png", "image/png")
        hide_btn = load_asset_as_base64(assets_path / "Windows" / "maximize-active.png", "image/png")
        shade_btn = load_asset_as_base64(assets_path / "Windows" / "shade-active.png", "image/png")
        check_off = load_asset_as_base64(assets_path / "Check-Radio" / "check-normal.png", "image/png")
        check_on = load_asset_as_base64(assets_path / "Check-Radio" / "check-active.png", "image/png")

        # Load scrollbar images
        scrollbar_trough_v = load_asset_as_base64(assets_path / "Scrollbars" / "trough-scrollbar-vert.png", "image/png")
        scrollbar_thumb_v = load_asset_as_base64(assets_path / "Scrollbars" / "slider-vertical.png", "image/png")
        scrollbar_up = load_asset_as_base64(assets_path / "Scrollbars" / "stepper-up.png", "image/png")
        scrollbar_down = load_asset_as_base64(assets_path / "Scrollbars" / "stepper-down.png", "image/png")

        # Load tab images
        tab_active = load_asset_as_base64(assets_path / "Tabs" / "tab-top-active.png", "image/png")
        tab_inactive = load_asset_as_base64(assets_path / "Tabs" / "tab-top.png", "image/png")

        html = load_template(template_file)
        html = html.replace("__ALL_GAMES__", json.dumps(all_games))
        html = html.replace("__TOP_N__", str(top_n))
        html = html.replace("__TOTAL_LIBRARY__", str(total_library))
        html = html.replace("__FONT_CHARCOAL__", font_charcoal)
        html = html.replace("__FONT_MONACO__", font_monaco)
        html = html.replace("__BACKGROUND_IMAGE__", background_image)
        html = html.replace("__BACKGROUND_IMAGE_CUSTOM__", background_image_custom)
        html = html.replace("__TITLEBAR_BG__", titlebar_bg)
        html = html.replace("__TITLE_STRIPES__", title_stripes)
        html = html.replace("__CLOSE_BTN__", close_btn)
        html = html.replace("__HIDE_BTN__", hide_btn)
        html = html.replace("__SHADE_BTN__", shade_btn)
        html = html.replace("__CHECK_OFF__", check_off)
        html = html.replace("__CHECK_ON__", check_on)
        html = html.replace("__SCROLLBAR_TROUGH_V__", scrollbar_trough_v)
        html = html.replace("__SCROLLBAR_THUMB_V__", scrollbar_thumb_v)
        html = html.replace("__SCROLLBAR_UP__", scrollbar_up)
        html = html.replace("__SCROLLBAR_DOWN__", scrollbar_down)
        html = html.replace("__TAB_ACTIVE__", tab_active)
        html = html.replace("__TAB_INACTIVE__", tab_inactive)

    Path(output_path).write_text(html, encoding="utf-8")
    print(f"Report generated: {output_path}")
    print(f"Total games in library: {total_library}")
    print(f"Total games with playtime: {total_games}")
    print(f"Total playtime: {total_playtime:.1f} hours")


def main():
    parser = argparse.ArgumentParser(
        description="Generate an HTML playtime report from a Lutris database."
    )
    parser.add_argument(
        "--db",
        default="pga.db",
        help="Path to the Lutris SQLite database (default: pga.db)"
    )
    parser.add_argument(
        "--output",
        default="report.html",
        help="Output HTML file path (default: report.html)"
    )
    parser.add_argument(
        "--top",
        type=int,
        default=10,
        help="Number of top games to show individually (default: 10)"
    )
    parser.add_argument(
        "--assets",
        default="templates/Platinum",
        help="Path to Platinum assets directory (default: templates/Platinum)"
    )
    parser.add_argument(
        "--background",
        default=None,
        help="Path to background image for tiling (default: Platinum stripes pattern)"
    )
    parser.add_argument(
        "--template",
        default="templates/platinum.html",
        help="HTML template file to use (default: templates/platinum.html). Ignored if --style is used."
    )
    parser.add_argument(
        "--style",
        choices=["brutalism", "glassmorphism", "neumorphism", "material", "flat", "synthwave", "vaporwave", "terminal", "highcontrast"],
        default=None,
        help="Modern style to use (brutalism, glassmorphism, neumorphism, material, flat, synthwave, vaporwave, terminal, highcontrast). Overrides --template."
    )

    args = parser.parse_args()

    if not Path(args.db).exists():
        print(f"Error: Database file not found: {args.db}")
        return 1

    if not Path(args.assets).exists():
        print(f"Error: Assets directory not found: {args.assets}")
        return 1

    # Determine style from --style or --template
    style = args.style

    # If no --style provided, check if --template points to a modern CSS file
    if not style and args.template.endswith('.css'):
        template_path = Path(args.template)
        style_name = template_path.stem  # e.g., "brutalism" from "brutalism.css"
        if style_name in MODERN_STYLES:
            style = style_name

    # Validate template/style
    if style and style in MODERN_STYLES:
        template_path = SCRIPT_DIR / "templates" / "modern.html"
        css_path = SCRIPT_DIR / "templates" / f"{style}.css"
        if not css_path.exists():
            print(f"Error: CSS file not found: {css_path}")
            return 1
    else:
        template_path = SCRIPT_DIR / args.template

    if not template_path.exists():
        print(f"Error: Template file not found: {template_path}")
        return 1

    generate_report(args.db, args.output, args.top, args.assets, args.template, args.background, style)
    return 0


if __name__ == "__main__":
    exit(main())
