"""Local settings storage for Advanced Glass Design Studio."""

from __future__ import annotations

import json
import os
import uuid
from pathlib import Path

from werkzeug.security import generate_password_hash

CONFIG_DIR = Path.home() / ".advanced_glass_studio"
CONFIG_FILE = CONFIG_DIR / "config.json"
OUTPUT_DIR = Path.home() / "AdvancedGlassStudio" / "output"
# Uploaded logo / favicon live here (outside the app folder, so re-uploading the
# code to the host never wipes them).
ASSET_DIR = CONFIG_DIR / "site_assets"

# ---------------------------------------------------------------------------
# Admin dashboard login — a single super-user account, separate from the
# regular per-customer accounts in users_store.py, used only to sign in at
# /admintools and manage user accounts/credits from the browser instead of the
# server terminal. Override the defaults on the server by setting the
# ADMIN_USERNAME / ADMIN_PASSWORD environment variables (e.g. in cPanel's
# "Setup Python App" env-vars panel) and restarting the app — do that once
# the site is live so the credentials aren't left at their defaults. The
# password is hashed on load; the plain value is never kept around or sent
# back to the browser.
# ---------------------------------------------------------------------------
ADMIN_USERNAME = os.environ.get("ADMIN_USERNAME", "mastertoolsui")
ADMIN_PASSWORD_HASH = generate_password_hash(os.environ.get("ADMIN_PASSWORD", "toolsmaster123@"))

# How many credits a single generated design costs (one image in a batch, or one
# refine call). Change this on the server without touching code by setting the
# CREDIT_COST_PER_DESIGN environment variable — e.g. in cPanel's "Setup Python App"
# env-vars panel — then restarting the app.
CREDIT_COST_PER_DESIGN = int(os.environ.get("CREDIT_COST_PER_DESIGN", "1"))

# The studio runs on Google Gemini only. The admin picks ONE model in the admin
# dashboard and it is used for every Gemini provider, while provider pools remain
# isolated by user/assignment/fallback scope.
# NOTE: if a model ID ever starts 404'ing, check
# https://ai.google.dev/gemini-api/docs/models for the current lineup and update this list
# (the admin dashboard also accepts a custom model ID).
GEMINI_MODELS = [
    "gemini-3.5-flash-lite",     # fastest / cheapest — the default
    "gemini-3.6-flash",
    "gemini-3.5-flash",
    "gemini-3.1-pro-preview",
]
DEFAULT_GEMINI_MODEL = "gemini-3.5-flash-lite"

# ---------------------------------------------------------------------------
# Square Canvas Sizes for Glass UI Design
# ---------------------------------------------------------------------------
CANVAS_SIZES = {
    "1000×1000": 1000,
}
DEFAULT_CANVAS_SIZE = "1000×1000"

# ---------------------------------------------------------------------------
# Glass UI Design — produces realistic "glassmorphism" elements (glass
# buttons/cards/tiles/circles) for stock asset packs.
# ---------------------------------------------------------------------------

GLASS_TYPES = {
    "Circle Icon Design": (
        "Shape class: Circle. HARD RULE: every glass element in the design is a perfect "
        "circle — draw its body as an actual <circle> element, or an <ellipse> with rx "
        "and ry within a few percent of each other at most. No rectangles, no rounded "
        "squares, no capsule shapes — circles only. Keep the silhouette perfectly round: "
        "the drop shadow, rim-light stroke, and highlight streak/glow must all stay "
        "inside or hug the circle's own boundary — never let a <feGaussianBlur> glow "
        "spread past the circle's edge and smear it into a soft, edgeless oval blob. "
        "The circle's outline itself must read as crisp and exact at every zoom level."
    ),
    "Rounded Icon Design": (
        "Shape class: Rounded Square Icon Tile. HARD RULE: every glass element is a "
        "roughly 1:1 square with generously rounded corners (large corner radius, "
        "app-icon style). Keep proportions close to square across all elements."
    ),
    "Rectangle Card Design": (
        "Shape class: Rounded Rectangle Card. HARD RULE: every glass element is a "
        "landscape rectangle (wider than tall) with rounded corners, like a UI panel "
        "or content card. Vary the width slightly between elements if there is more "
        "than one, but keep the same rounded-rectangle card language."
    ),
    "Button Design": (
        "Shape class: Pill / Capsule Button. HARD RULE: every glass element is a short, "
        "wide capsule shape with fully rounded (semi-circular) ends, like a button. "
        "Draw its body as a <rect> whose rx is EXACTLY half of its height, so the left "
        "and right ends form true semicircles — not a full circle, and not a rectangle "
        "with only slightly rounded corners. Keep that rx-to-height ratio precise and "
        "the straight top/bottom edges crisp: never let blur, glow, or gradient effects "
        "soften those edges or round them further into a lozenge/blob shape."
    ),
    "Mixed Shape UI Design": (
        "Shape class: Mixed Set. Use a deliberate variety across the elements — combine "
        "circles, rounded squares, rounded rectangles, and pill shapes so the set reads "
        "as one cohesive glass UI kit sheet, the way a stock 'glassmorphism asset pack' "
        "sample image looks. No two adjacent elements should be identical in shape."
    ),
}
DEFAULT_GLASS_TYPE = "Mixed Shape UI Design"

GLASS_STYLES = {
    "Clear Glass (Bright Highlight)": (
        "Rendering technique: Clear Glass. HARD RULE: the glass fill must be a very "
        "light, low-opacity gradient (near-white/near-transparent, opacity roughly "
        "0.08-0.25) so whatever is behind it would show through. Every element needs "
        "a crisp diagonal bright highlight streak (a thin bright-white semi-transparent "
        "band running corner to corner or across the top) plus a subtle 1px bright "
        "rim-light stroke tracing the outer edge. Use <linearGradient>/<radialGradient> "
        "for the tint and soft <feGaussianBlur> filters for the highlight streak's glow "
        "— this is the one style category in this app where gradients and blur filters "
        "are REQUIRED, not forbidden."
    ),
    "Frosted / Matte Glass": (
        "Rendering technique: Frosted / Matte Glass. HARD RULE: slightly higher opacity "
        "translucent white fill (roughly 0.20-0.40) than Clear Glass, with a soft, wide, "
        "heavily blurred highlight (large feGaussianBlur radius) instead of a crisp streak "
        "— it should read as diffused, satin, semi-opaque frosted glass rather than perfectly "
        "clear glass. Edge stroke should be soft and faint, not a sharp bright line."
    ),
    "Tinted Color Glass": (
        "Rendering technique: Tinted Color Glass. HARD RULE: same glass construction as "
        "Clear Glass (gradient fill, blurred highlight streak, bright rim-light edge) but "
        "the gradient fill is tinted with the requested accent color at low opacity "
        "(roughly 0.15-0.35) instead of staying neutral white, so the glass reads as "
        "colored glass rather than clear glass."
    ),
}
DEFAULT_GLASS_STYLE = "Clear Glass (Bright Highlight)"

# ---------------------------------------------------------------------------
# Highlight Intensity — a second, independent knob on top of Glass Style:
# Glass Style decides *what kind* of glass it is (clear/frosted/tinted); this
# decides *how strong* the shine/highlight reads once that style is picked.
# ---------------------------------------------------------------------------
HIGHLIGHT_INTENSITIES = {
    "Subtle": (
        "Highlight Intensity: Subtle. Keep the bright highlight streak and rim-light "
        "thin, soft-edged, and low-contrast. The glass should look calm, refined, and "
        "understated — good for backgrounds and secondary UI elements, not flashy."
    ),
    "Balanced": (
        "Highlight Intensity: Balanced. Use a clearly visible but tasteful highlight "
        "streak and rim-light — bright enough to read unmistakably as glass at a glance, "
        "without overpowering the rest of the design. This is the safe, general-purpose default."
    ),
    "Dramatic": (
        "Highlight Intensity: Dramatic. Make the highlight streak and rim-light bold, "
        "crisp, and high-contrast, and add one extra small glossy specular blob. The "
        "glass should look premium and eye-catching, like a hero shot for a marketing page."
    ),
}
DEFAULT_HIGHLIGHT_INTENSITY = "Balanced"

# Single element per design (not multiple elements in a row like before)
GLASS_COUNTS = ["1"]
DEFAULT_GLASS_COUNT = "1"

def get_canvas_size(size_label: str) -> int:
    """Return the fixed server canvas size. Client input is intentionally ignored."""
    return 1000

def glass_canvas_size(size_label: str) -> tuple[int, int]:
    """Returns square canvas (width, height)"""
    size = get_canvas_size(size_label)
    return (size, size)

# Background color options
BACKGROUND_COLORS = {
    "🎲 Random": "random",
    "🌙 Dark Blue": "#1a2847",
    "🌃 Deep Purple": "#2d1b4e",
    "🌲 Dark Green": "#1b3d2e",
    "🔴 Deep Red": "#3d1a1a",
    "⚫ Black": "#0a0a0a",
    "🌊 Ocean Blue": "#0f3e6b",
    "🌸 Rose": "#4a1f35",
}
DEFAULT_BACKGROUND = "🎲 Random"

AUTO_PROVIDER_ID = "__auto__"
AUTO_PROVIDER_LABEL = "⚡ Auto (rotate all keys)"

DEFAULTS = {
    "providers": [],
    "gemini_model": DEFAULT_GEMINI_MODEL,
    "active_provider_id": "",
    "appearance_mode": "dark",
    "default_color": "auto",
    "default_bg": DEFAULT_BACKGROUND,
    "default_variant_count": 1,
    "default_glass_type": DEFAULT_GLASS_TYPE,
    "default_glass_style": DEFAULT_GLASS_STYLE,
    "default_highlight_intensity": DEFAULT_HIGHLIGHT_INTENSITY,
    "default_glass_count": DEFAULT_GLASS_COUNT,
    "default_canvas_size": DEFAULT_CANVAS_SIZE,
    # Admin-curated shortcut links shown to every user in the app (e.g. a
    # Facebook group, Telegram group, or a new-tool announcement) — managed
    # entirely from the /admintools dashboard, no code changes needed to add,
    # edit, or remove one. Each item: {"id", "label", "url"}.
    "resource_links": [],
    # Site-wide branding + maintenance switch, managed from /admintools -> Site Settings.
    "site": {},
}

# ---------------------------------------------------------------------------
# Site settings (title, logo, favicon, texts, maintenance mode, credit cost).
# Anything the admin leaves blank falls back to these defaults.
# ---------------------------------------------------------------------------
SITE_DEFAULTS = {
    "site_title": "Glass Design Generator",          # browser-tab title
    "brand_name": "Glass Design Generator",          # header name (last word gets the accent colour)
    "subtitle": "Create stunning glass UI designs with AI",
    "tagline": "Turn your ideas into beautiful glass UI elements",
    "badge_text": "AI Powered",
    "login_text": "Sign in with your studio account to continue.",
    "logo_file": "",
    "favicon_file": "",
    "maintenance": False,
    "maintenance_title": "We'll be back soon",
    "maintenance_message": "The studio is under maintenance right now. Please check back in a little while.",
    "credit_cost": None,                             # None = use CREDIT_COST_PER_DESIGN
}
SITE_TEXT_LIMITS = {
    "site_title": 80, "brand_name": 60, "subtitle": 120, "tagline": 140, "badge_text": 30,
    "login_text": 160, "maintenance_title": 80, "maintenance_message": 500,
}

def get_site(config: dict) -> dict:
    out = dict(SITE_DEFAULTS)
    saved = (config or {}).get("site") or {}
    for key in SITE_DEFAULTS:
        val = saved.get(key)
        if key in SITE_TEXT_LIMITS or key in ("logo_file", "favicon_file"):
            if isinstance(val, str) and val.strip():
                out[key] = val.strip()
        elif key == "maintenance":
            out[key] = bool(val)
        elif key == "credit_cost":
            if isinstance(val, int) and not isinstance(val, bool) and val >= 0:
                out[key] = val
    return out

def get_credit_cost(config: dict) -> int:
    """Credits per design: the admin's Site Settings value, else the env-var default."""
    val = get_site(config)["credit_cost"]
    return CREDIT_COST_PER_DESIGN if val is None else val

def new_provider(label: str = "") -> dict:
    """A blank Gemini API-key entry. (The model is global — see get_gemini_model.)"""
    return {
        "id": uuid.uuid4().hex,
        "type": "gemini",
        "label": label or "Gemini key",
        "api_key": "",
    }

def get_gemini_model(config: dict) -> str:
    model = str((config or {}).get("gemini_model") or "").strip()
    return model or DEFAULT_GEMINI_MODEL

def load_config() -> dict:
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    if not CONFIG_FILE.exists():
        return dict(DEFAULTS)
    try:
        data = json.loads(CONFIG_FILE.read_text(encoding="utf-8"))
        merged = dict(DEFAULTS)
        merged.update(data)
        if not isinstance(merged.get("providers"), list):
            merged["providers"] = []
        return merged
    except Exception:
        return dict(DEFAULTS)

def save_config(config: dict) -> None:
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    CONFIG_FILE.write_text(json.dumps(config, indent=2, ensure_ascii=False), encoding="utf-8")

def get_provider(config: dict, provider_id: str):
    for p in config.get("providers", []):
        if p.get("id") == provider_id:
            return p
    return None

def usable_providers(config: dict):
    return [p for p in config.get("providers", []) if p.get("api_key")]

def get_active_provider(config: dict):
    active = get_provider(config, config.get("active_provider_id", ""))
    if active and active.get("api_key"):
        return active
    usable = usable_providers(config)
    return usable[0] if usable else None
