import hashlib
import random
from datetime import date

from app.config import settings
from app.config.config_storage import get_config_storage


def _seed(client_slug: str, *parts) -> int:
    raw = "|".join([client_slug or "default", *[str(p) for p in parts]])
    return int(hashlib.md5(raw.encode("utf-8")).hexdigest()[:8], 16)


def _rng(client_slug: str, *parts) -> random.Random:
    return random.Random(_seed(client_slug, *parts))


def _safe_client_slug(client):
    if client and getattr(client, "slug", None):
        return client.slug
    return "default"


def build_branch_payload(client, branch_id: str, month: int, year: int):
    if branch_id not in settings.BRANCHES:
        raise ValueError(f"Invalid branch_id: {branch_id}")
    client_slug = _safe_client_slug(client)
    branch_cfg = settings.BRANCHES[branch_id]
    branch_rng = _rng(client_slug, "branch", branch_id, month, year)
    departments = []
    gp_violations_total = 0
    total_rev = 0.0
    total_gp = 0.0
    for company_id, company in branch_cfg["companies"].items():
        r = _rng(client_slug, "dept", branch_id, company_id, month, year)
        target = float(company["target"])
        revenue = round(max(target * r.uniform(0.75, 1.2), 0), 2)
        gp_margin = round(r.uniform(31.0, 58.0), 2)
        gp_dollars = round(revenue * gp_margin / 100.0, 2)
        if gp_margin >= 50:
            gp_color = "green"
        elif gp_margin >= 40:
            gp_color = "yellow"
        else:
            gp_color = "red"
        gp_violations = r.randint(0, 7)
        gp_violations_total += gp_violations
        total_rev += revenue
        total_gp += gp_dollars
        departments.append(
            {
                "name": company["name"],
                "current": revenue,
                "breakeven": company["breakeven"],
                "target": company["target"],
                "gross_profit_margin": gp_margin,
                "gross_profit": gp_dollars,
                "gp_color": gp_color,
                "gp_violations": gp_violations,
            }
        )
    branch_gp_margin = round((total_gp / total_rev) * 100.0, 2) if total_rev > 0 else None
    marketing = {
        "google_cost": round(branch_rng.uniform(7000, 19000), 2),
        "google_clicks": branch_rng.randint(1200, 4200),
        "google_leads": branch_rng.randint(90, 280),
        "google_cost_per_lead": round(branch_rng.uniform(45, 95), 2),
        "meta_cost": round(branch_rng.uniform(3000, 12000), 2),
        "meta_clicks": branch_rng.randint(700, 2600),
        "meta_leads": branch_rng.randint(45, 180),
        "meta_cost_per_lead": round(branch_rng.uniform(50, 110), 2),
        "total_quote_value": round(branch_rng.uniform(120000, 540000), 2),
        "total_sales_value": round(branch_rng.uniform(90000, 460000), 2),
    }
    return {
        "id": branch_id,
        "name": branch_cfg["name"],
        "departments": departments,
        "gross_profit_margin": branch_gp_margin,
        "gp_violations_total": gp_violations_total,
        "marketing": marketing,
        "google_review_totals_by_branch": {
            settings.BRANCHES[b]["name"]: _rng(client_slug, "reviews", b, month, year).randint(6, 48)
            for b in settings.BRANCHES.keys()
        },
    }


def build_overview_payload(client, month: int, year: int):
    branches = [build_branch_payload(client, b, month, year) for b in settings.BRANCHES.keys()]
    total_revenue = 0.0
    total_gp = 0.0
    for b in branches:
        branch_revenue = sum((d.get("current", 0.0) or 0.0) for d in b["departments"])
        total_revenue += branch_revenue
        if b.get("gross_profit_margin") is not None and branch_revenue > 0:
            total_gp += branch_revenue * (b["gross_profit_margin"] / 100.0)
    overall_gp_margin = round((total_gp / total_revenue) * 100.0, 2) if total_revenue > 0 else None
    overall_gp_color = None
    if overall_gp_margin is not None:
        overall_gp_color = get_config_storage().get_gp_color("Electrical", overall_gp_margin)
    return {
        "branches": branches,
        "month": month,
        "year": year,
        "gross_profit_margin": overall_gp_margin,
        "overall_gp_color": overall_gp_color,
    }


def build_gp_violations_payload(client, month: int, year: int):
    branches = []
    company_total = 0
    for branch_id, branch_cfg in settings.BRANCHES.items():
        total = 0
        depts = []
        for company_id, company in branch_cfg["companies"].items():
            v = _rng(_safe_client_slug(client), "gpv", branch_id, company_id, month, year).randint(0, 7)
            total += v
            depts.append({"name": company["name"], "gp_violations": v})
        company_total += total
        branches.append({"id": branch_id, "gp_violations_total": total, "departments": depts})
    return {"month": month, "year": year, "from_date": None, "to_date": None, "branches": branches, "company_total": company_total}


def _kpi_target_skeleton():
    return get_config_storage().get_kpi_targets()


def build_kpi_month_payload(client, month: int, year: int):
    targets = _kpi_target_skeleton()
    payload = {}
    for branch_name, depts in targets.items():
        payload[branch_name] = {}
        for dept_name, metrics in depts.items():
            payload[branch_name][dept_name] = {}
            for metric_key, metric in metrics.items():
                rr = _rng(_safe_client_slug(client), "kpi-month", branch_name, dept_name, metric_key, month, year)
                base = float(metric.get("target", 0))
                if metric.get("aggregation") == "sum":
                    val = round(max(base / 3.0 * rr.uniform(0.75, 1.2), 0), 2)
                else:
                    val = round(max(base * rr.uniform(0.75, 1.2), 0), 2)
                payload[branch_name][dept_name][metric_key] = val
    return payload


def build_kpi_quarter_payload(client, month: int, year: int):
    targets = _kpi_target_skeleton()
    payload = {}
    for branch_name, depts in targets.items():
        payload[branch_name] = {}
        for dept_name, metrics in depts.items():
            payload[branch_name][dept_name] = {}
            for metric_key, metric in metrics.items():
                rr = _rng(_safe_client_slug(client), "kpi-quarter", branch_name, dept_name, metric_key, month, year)
                base = float(metric.get("target", 0))
                if metric.get("aggregation") == "sum":
                    v1 = round(max(base / 3.0 * rr.uniform(0.7, 1.2), 0), 2)
                    v2 = round(max(base / 3.0 * rr.uniform(0.7, 1.2), 0), 2)
                    v3 = round(max(base / 3.0 * rr.uniform(0.7, 1.2), 0), 2)
                else:
                    v1 = round(max(base * rr.uniform(0.7, 1.2), 0), 2)
                    v2 = round(max(base * rr.uniform(0.7, 1.2), 0), 2)
                    v3 = round(max(base * rr.uniform(0.7, 1.2), 0), 2)
                payload[branch_name][dept_name][metric_key] = [v1, v2, v3]
                if metric_key == "workloadForm":
                    payload[branch_name][dept_name]["workloadFormCount"] = [rr.randint(8, 25), rr.randint(8, 25), rr.randint(8, 25)]
                if metric_key == "clientReviews":
                    payload[branch_name][dept_name]["clientReviewsTotal"] = [rr.randint(3, 16), rr.randint(3, 16), rr.randint(3, 16)]
    return payload


def build_misc_payload(client, branch_id: str):
    if branch_id not in settings.BRANCHES:
        raise ValueError(f"Invalid branch_id: {branch_id}")
    client_slug = _safe_client_slug(client)
    branch_cfg = settings.BRANCHES[branch_id]
    r = _rng(client_slug, "misc", branch_id)
    today = date.today()
    time_utilisation = []
    for i in range(8):
        week = date.fromordinal(today.toordinal() - (7 * (7 - i)))
        time_utilisation.append(
            {
                "week": week.isoformat(),
                "job_hours": round(r.uniform(260, 380), 1),
                "quoting_hours": round(r.uniform(35, 95), 1),
                "non_job_hours": round(r.uniform(25, 80), 1),
            }
        )
    job_efficiency = [
        {"employee": f"{branch_cfg['name']} Tech {idx + 1}", "ratio": round(r.uniform(0.75, 1.35), 2)}
        for idx in range(8)
    ]
    wip_departments = {}
    total_jobs = 0
    total_value = 0.0
    for _, c in branch_cfg["companies"].items():
        jc = r.randint(6, 30)
        wv = round(r.uniform(18000, 140000), 2)
        total_jobs += jc
        total_value += wv
        wip_departments[c["name"]] = {"job_count": jc, "wip_value": wv}
    avg_time_to_invoice = {c["name"]: round(r.uniform(0.6, 3.4), 2) for _, c in branch_cfg["companies"].items()}
    return {
        "quote_data": {
            "quote_conversion_rate": round(r.uniform(42.0, 71.0), 2),
            "quotes_created": r.randint(40, 130),
            "quotes_won": r.randint(20, 90),
            "total_quote_value": round(r.uniform(150000, 520000), 2),
            "won_quote_value": round(r.uniform(90000, 410000), 2),
        },
        "subscriber_count": r.randint(1800, 9200),
        "time_utilisation": time_utilisation,
        "job_efficiency": job_efficiency,
        "wip_jobs": {"job_count": total_jobs, "wip_value": round(total_value, 2), "departments": wip_departments},
        "avg_time_to_invoice": avg_time_to_invoice,
    }
