"""get_portfolio_data -- Bulk portfolio snapshot from the LMA.

Runs a single SOQL query to fetch all active production licenses,
groups by customer, and returns a compact per-customer summary.
Writes full data to portfolio/portfolio-data.json.

The AI interprets the data for scoring, prioritisation, and insights.
"""

import json
import logging
from collections import defaultdict
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from ..utils import sf_cli, state

logger = logging.getLogger(__name__)

LICENSE_FIELDS = (
    "sfLma__Account__r.Name, "
    "sfLma__Account__r.Id, "
    "Package_Name__c, "
    "Package_Version_Number__c, "
    "sfLma__License_Status__c, "
    "sfLma__Expiration_Date__c, "
    "Days_To_Expire__c"
)

TOOL_DEFINITION = {
    "name": "get_portfolio_data",
    "description": (
        "Fetch a snapshot of ALL active production licenses from the "
        "CloudSense License Management Portal. Groups results by customer "
        "and returns a compact summary (customer name, package count, "
        "nearest expiry, license count). Writes full data to "
        "portfolio/portfolio-data.json. Use this for any cross-customer "
        "analysis: renewal risks, portfolio overview, customer comparison. "
        "Requires connect_lma first."
    ),
    "inputSchema": {
        "type": "object",
        "properties": {
            "working_directory": {
                "type": "string",
                "description": "Workspace directory. The AI passes this automatically.",
            },
        },
        "required": [],
    },
}


def _query_all_active_licenses(lma_alias: str) -> list[dict[str, Any]]:
    query = (
        f"SELECT {LICENSE_FIELDS} "
        f"FROM sfLma__License__c "
        f"WHERE sfLma__Is_Sandbox__c = false "
        f"AND sfLma__License_Status__c IN ('Active', 'Trial') "
        f"AND sfLma__Account__r.Name != null "
        f"ORDER BY sfLma__Account__r.Name"
    )
    return sf_cli.lma_query(query, lma_alias)


def _group_by_customer(
    licenses: list[dict[str, Any]],
) -> dict[str, dict[str, Any]]:
    """Group licenses by customer account, compute per-customer metrics."""
    customers: dict[str, dict[str, Any]] = {}

    for lic in licenses:
        acct_ref = lic.get("sfLma__Account__r")
        if not isinstance(acct_ref, dict):
            continue
        acct_name = acct_ref.get("Name", "Unknown")
        acct_id = acct_ref.get("Id", "")

        if acct_name not in customers:
            customers[acct_name] = {
                "account_id": acct_id,
                "packages": defaultdict(list),
                "statuses": set(),
                "nearest_expiry_days": None,
                "license_count": 0,
            }

        cust = customers[acct_name]
        cust["license_count"] += 1

        status = lic.get("sfLma__License_Status__c") or "Unknown"
        cust["statuses"].add(status)

        pkg_name = lic.get("Package_Name__c") or "Unknown"
        cust["packages"][pkg_name].append(
            lic.get("Package_Version_Number__c") or "?"
        )

        days = lic.get("Days_To_Expire__c")
        if days is not None:
            try:
                d = float(days)
                if cust["nearest_expiry_days"] is None or d < cust["nearest_expiry_days"]:
                    cust["nearest_expiry_days"] = d
            except (ValueError, TypeError):
                pass

    result = {}
    for name, cust in customers.items():
        result[name] = {
            "account_id": cust["account_id"],
            "license_count": cust["license_count"],
            "package_count": len(cust["packages"]),
            "statuses": sorted(cust["statuses"]),
            "packages": {
                pkg: sorted(set(versions))
                for pkg, versions in cust["packages"].items()
            },
            "nearest_expiry_days": cust["nearest_expiry_days"],
        }
    return result


def _write_portfolio_json(
    working_dir: Path,
    customers: dict[str, dict[str, Any]],
    total_licenses: int,
) -> Path:
    portfolio_dir = working_dir / "portfolio"
    portfolio_dir.mkdir(parents=True, exist_ok=True)
    out_path = portfolio_dir / "portfolio-data.json"
    out_path.write_text(json.dumps({
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "total_licenses": total_licenses,
        "customer_count": len(customers),
        "customers": customers,
    }, indent=2, default=str))
    return out_path


async def run(arguments: dict[str, Any]) -> str:
    """Execute the get_portfolio_data tool."""
    state.set_working_dir(arguments.get("working_directory"))
    current_state = state.load()
    lma_alias = current_state.get("lma_org_alias") or "cs-lma"

    licenses = _query_all_active_licenses(lma_alias)

    if not licenses:
        return (
            "STATUS: NO_DATA\n\n"
            "No active production licenses found in the LMA. "
            "Verify connect_lma was called and the LMA org has license data."
        )

    customers = _group_by_customer(licenses)
    artifact_path = _write_portfolio_json(
        state.get_working_dir(), customers, len(licenses),
    )

    sorted_customers = sorted(
        customers.items(),
        key=lambda x: (
            x[1]["nearest_expiry_days"]
            if x[1]["nearest_expiry_days"] is not None
            else 99999
        ),
    )

    lines = [
        "STATUS: READY\n",
        f"## Portfolio Snapshot\n",
        f"- **Customers:** {len(customers)}",
        f"- **Total active production licenses:** {len(licenses)}",
        f"- **Data:** `{artifact_path}`\n",
    ]

    expiring_90 = [
        (n, c) for n, c in sorted_customers
        if c["nearest_expiry_days"] is not None and c["nearest_expiry_days"] < 90
    ]
    if expiring_90:
        lines.append(f"### Renewal Risk (expiry < 90 days): {len(expiring_90)} customers\n")
        lines.append("| Customer | Packages | Licenses | Status | Nearest Expiry (days) |")
        lines.append("|----------|----------|----------|--------|-----------------------|")
        for name, cust in expiring_90:
            days = int(cust["nearest_expiry_days"])
            status = ", ".join(cust["statuses"])
            lines.append(
                f"| {name} | {cust['package_count']} | "
                f"{cust['license_count']} | {status} | {days} |"
            )

    lines.append(f"\n### All Customers\n")
    lines.append("| Customer | Packages | Licenses | Status | Nearest Expiry (days) |")
    lines.append("|----------|----------|----------|--------|-----------------------|")
    for name, cust in sorted_customers:
        days = cust["nearest_expiry_days"]
        days_str = str(int(days)) if days is not None else "n/a"
        status = ", ".join(cust["statuses"])
        lines.append(
            f"| {name} | {cust['package_count']} | "
            f"{cust['license_count']} | {status} | {days_str} |"
        )

    lines.append(
        "\n\nPresent this portfolio snapshot to the user. Offer to:\n"
        "- Dive deeper into any specific customer (use find_customer)\n"
        "- Identify renewal risks, version currency, or upsell opportunities\n"
        "- Save findings as a shareable report (use save_report)\n"
    )

    return "\n".join(lines)
