import re
from loguru import logger
from sqlalchemy.orm import Session
from sqlalchemy import and_
from app.models.miner import Miner
from app.services.openrouter import fetch_miners_from_ai


HASHRATE_CONVERSIONS = {
    "ph/s": 1000.0,
    "th/s": 1.0,
    "gh/s": 0.001,
    "mh/s": 0.000001,
    "kh/s": 0.000000001,
    "h/s": 0.000000000001,
}


def normalize_hashrate(value: any, unit: str = "TH/s") -> float:
    """Normalize any hashrate to TH/s."""
    try:
        numeric = float(str(value).replace(",", "").strip())
        multiplier = HASHRATE_CONVERSIONS.get(unit.lower(), 1.0)
        return round(numeric * multiplier, 8)
    except (ValueError, TypeError):
        logger.warning(f"Cannot normalize hashrate: {value} {unit}")
        return 0.0


def clean_miner_data(raw: dict) -> dict | None:
    """Validate and clean a miner record from AI response."""
    try:
        name = str(raw.get("name", "")).strip().lower()
        brand = str(raw.get("brand", "")).strip()
        miner_type = str(raw.get("type", "")).strip().upper()
        power = raw.get("power_consumption", 0)
        supported = raw.get("supported_coins", "")

        # Strip extra whitespace from all string fields
        name = re.sub(r"\s+", " ", name)
        brand = re.sub(r"\s+", " ", brand).strip()

        if not name or not brand:
            logger.warning(f"Skipping miner with missing name/brand: {raw}")
            return None

        if miner_type not in ("ASIC", "GPU"):
            miner_type = "ASIC"

        # Normalize hashrate
        hashrate_raw = raw.get("hashrate", 0)
        hashrate_unit = str(raw.get("hashrate_unit", "TH/s")).strip()
        hashrate_ths = normalize_hashrate(hashrate_raw, hashrate_unit)

        if hashrate_ths <= 0:
            logger.warning(f"Skipping miner with invalid hashrate: {name}")
            return None

        # Normalize power
        try:
            power_w = int(float(str(power).replace(",", "")))
        except (ValueError, TypeError):
            power_w = 0

        # Calculate efficiency (J/TH)
        efficiency = round(power_w / hashrate_ths, 4) if hashrate_ths > 0 else 0.0

        # Normalize supported_coins
        if isinstance(supported, list):
            supported = ",".join(supported)
        coins = ",".join(
            c.strip().upper()
            for c in str(supported).split(",")
            if c.strip()
        )

        return {
            "name": name,
            "brand": brand,
            "type": miner_type,
            "hashrate": hashrate_ths,
            "hashrate_unit": "TH/s",
            "power_consumption": power_w,
            "efficiency": efficiency,
            "supported_coins": coins,
        }
    except Exception as e:
        logger.error(f"Error cleaning miner data: {e} | Raw: {raw}")
        return None


def upsert_miner(db: Session, data: dict) -> str:
    """
    Insert or update a miner record.
    Returns: 'inserted' | 'updated' | 'skipped'
    """
    existing = (
        db.query(Miner)
        .filter(
            and_(
                Miner.name == data["name"],
                Miner.hashrate == data["hashrate"],
            )
        )
        .first()
    )

    if existing is None:
        miner = Miner(**data)
        db.add(miner)
        db.flush()
        logger.debug(f"Inserted miner: {data['name']}")
        return "inserted"

    if existing.is_complete():
        logger.debug(f"Skipped (complete): {data['name']}")
        return "skipped"

    # Update incomplete record
    for key, value in data.items():
        if value and not getattr(existing, key, None):
            setattr(existing, key, value)
    db.flush()
    logger.debug(f"Updated miner: {data['name']}")
    return "updated"


async def run_seeder(db: Session) -> dict:
    """Fetch miners from AI and seed the database."""
    logger.info("Starting miner seeder...")

    raw_miners = await fetch_miners_from_ai()
    logger.info(f"Received {len(raw_miners)} raw miners from AI")

    stats = {"fetched": len(raw_miners), "inserted": 0, "updated": 0, "skipped": 0, "errors": 0}

    try:
        for raw in raw_miners:
            cleaned = clean_miner_data(raw)
            if not cleaned:
                stats["errors"] += 1
                continue

            result = upsert_miner(db, cleaned)
            stats[result] += 1

        db.commit()
        logger.info(f"Seeder completed: {stats}")
    except Exception as e:
        db.rollback()
        logger.error(f"Seeder failed: {e}")
        raise

    return stats
