# retoor <retoor@molodetz.nl>

from __future__ import annotations

import os
from datetime import datetime, timedelta

from devplacepy.cache import TTLCache
from devplacepy.database import db, get_table
from devplacepy.utils import generate_uid

from .. import economy
from .common import _iso


SATURATION_TTL = int(os.environ.get("DEVPLACE_MARKET_SATURATION_TTL", "30"))


_saturation_cache = TTLCache(ttl=SATURATION_TTL, max_size=32)


def _ticks():
    return get_table("game_market_ticks")


def _hour_bucket(now: datetime) -> str:
    return now.strftime("%Y-%m-%dT%H")


def record_harvest_tick(crop_key: str, now: datetime) -> None:
    with db:
        db.query(
            "INSERT INTO game_market_ticks (uid, crop_key, hour_bucket, harvests, updated_at) "
            "VALUES (:uid, :crop_key, :hour_bucket, 1, :now) "
            "ON CONFLICT(crop_key, hour_bucket) DO UPDATE SET "
            "harvests = harvests + 1, updated_at = :now",
            uid=generate_uid(),
            crop_key=crop_key,
            hour_bucket=_hour_bucket(now),
            now=_iso(now),
        )
    _saturation_cache.pop(f"{crop_key}:{economy.MARKET_WINDOW_HOURS}")


def recent_harvests(crop_key: str, window_hours: int) -> int:
    cache_key = f"{crop_key}:{window_hours}"
    cached = _saturation_cache.get(cache_key)
    if cached is not None:
        return cached
    from .common import _now

    cutoff = _hour_bucket(_now() - timedelta(hours=window_hours))
    row = db.query(
        "SELECT COALESCE(SUM(harvests), 0) AS total FROM game_market_ticks "
        "WHERE crop_key = :crop_key AND hour_bucket >= :cutoff",
        crop_key=crop_key,
        cutoff=cutoff,
    )
    total = 0
    for result in row:
        total = int(result["total"] or 0)
        break
    _saturation_cache.set(cache_key, total)
    return total


def active_farms() -> int:
    cached = _saturation_cache.get("active_farms")
    if cached is not None:
        return cached
    rows = db.query(
        "SELECT COUNT(*) AS active FROM game_farms WHERE COALESCE(harvests_week, 0) > 0"
    )
    total = 1
    for row in rows:
        total = max(1, int(row.get("active") or 0))
        break
    _saturation_cache.set("active_farms", total)
    return total


def _saturation_for(crop_key: str) -> float:
    crop = economy.crop_for(crop_key)
    if crop is None:
        return 1.0
    recent = recent_harvests(crop_key, economy.MARKET_WINDOW_HOURS)
    return economy.market_saturation_factor(
        economy.supply_days(crop, recent, active_farms())
    )


def market_pressure() -> float:
    worst = 1.0
    for key in economy.MARKET_PRESSURE_CROPS:
        worst = min(worst, _saturation_for(key))
    return 1.0 - worst


def market_factor_for(crop_key: str) -> float:
    if economy.crop_for(crop_key) is None:
        return 1.0
    saturation = _saturation_for(crop_key)
    if saturation < 1.0:
        return saturation
    return economy.market_buff_factor(crop_key, market_pressure())


def prune_ticks(older_than_hours: int = 96) -> int:
    from sqlalchemy import text

    from .common import _now

    cutoff = _hour_bucket(_now() - timedelta(hours=older_than_hours))
    with db:
        result = db.executable.execute(
            text("DELETE FROM game_market_ticks WHERE hour_bucket < :cutoff"),
            {"cutoff": cutoff},
        )
        return result.rowcount


def prune_steals(older_than_days: int = 60) -> int:
    from datetime import timedelta as _timedelta

    from sqlalchemy import text

    from .common import _iso, _now

    cutoff = _iso(_now() - _timedelta(days=older_than_days))
    with db:
        result = db.executable.execute(
            text("DELETE FROM game_steals WHERE stolen_at < :cutoff"), {"cutoff": cutoff}
        )
        return result.rowcount
