"""connect_lma tool -- authorize the CloudSense LMA org.

This is the entry point for the LMA-first customer discovery flow.
It authorizes the License Management App (LMA) Salesforce org and
discovers the sfLma data model (field lists) so that downstream
tools can build queries using only fields that actually exist.
"""

import logging
from typing import Any

from ..utils import sf_cli, state

logger = logging.getLogger(__name__)

DEFAULT_LMA_ALIAS = "cs-lma"
DEFAULT_LMA_LOGIN_URL = "https://login.salesforce.com"

SFLMA_OBJECTS_TO_DESCRIBE = [
    "sfLma__License__c",
    "sfLma__Package__c",
    "sfLma__Package_Version__c",
]

TOOL_DEFINITION = {
    "name": "connect_lma",
    "description": (
        "Authorize the CloudSense License Management App (LMA) Salesforce org. "
        "This is the FIRST tool to call for any customer inquiry -- it connects "
        "to the LMA org where all customer licenses, packages, and subscriber "
        "information are managed. After authorization it discovers the sfLma "
        "data model so downstream tools use only fields that actually exist. "
        "Stores the LMA org alias in state for use by find_customer and "
        "get_customer_licenses."
    ),
    "inputSchema": {
        "type": "object",
        "properties": {
            "org_alias": {
                "type": "string",
                "description": (
                    "Alias for the LMA org. Defaults to 'cs-lma'. "
                    "If the org is already authorized under this alias, "
                    "the tool skips login."
                ),
            },
            "instance_url": {
                "type": "string",
                "description": (
                    "Salesforce login URL for the LMA org. "
                    "Defaults to 'https://login.salesforce.com'. "
                    "Override if the LMA org uses a custom domain "
                    "(e.g., 'https://cloudsense.my.salesforce.com/')."
                ),
            },
            "working_directory": {
                "type": "string",
                "description": (
                    "Absolute path to the working directory. Used for state "
                    "file storage. If not provided, LMA connection info is "
                    "returned but not persisted to state."
                ),
            },
        },
        "required": [],
    },
}


def _find_lma_org(alias: str) -> dict[str, Any] | None:
    """Check if an org with the given alias is already authorized."""
    try:
        orgs = sf_cli.list_orgs()
        for org in orgs:
            if org.get("alias") == alias:
                return org
    except sf_cli.SfCliError:
        pass
    return None


def _validate_org(alias: str) -> dict[str, Any] | None:
    """Validate that the org is still accessible."""
    try:
        data = sf_cli.display_org(alias)
        return data.get("result", {})
    except sf_cli.SfCliError:
        return None


def _describe_lma_objects(
    alias: str,
) -> dict[str, list[str]]:
    """Discover field names on sfLma objects by running sf sobject describe.

    Returns a dict mapping object API name to a list of field API names.
    On failure for an object, stores an empty list (graceful degradation).
    """
    fields_by_object: dict[str, list[str]] = {}
    for obj_name in SFLMA_OBJECTS_TO_DESCRIBE:
        try:
            desc = sf_cli.describe_sobject(obj_name, alias)
            field_list = desc.get("fields", [])
            fields_by_object[obj_name] = [
                f.get("name", "") for f in field_list if f.get("name")
            ]
            logger.info(
                "Discovered %d fields on %s",
                len(fields_by_object[obj_name]),
                obj_name,
            )
        except sf_cli.SfCliError as e:
            logger.warning("Could not describe %s: %s", obj_name, e)
            fields_by_object[obj_name] = []
    return fields_by_object


async def run(arguments: dict[str, Any]) -> str:
    """Execute the connect_lma tool."""
    alias = arguments.get("org_alias") or DEFAULT_LMA_ALIAS
    instance_url = arguments.get("instance_url")
    working_dir_str = arguments.get("working_directory")

    report: list[str] = []
    report.append("# Connect to CloudSense LMA Org\n")

    # ── 1. Check if already authorized ──────────────────────────
    report.append("## Authorization\n")

    org_info = _validate_org(alias)
    if org_info:
        username = org_info.get("username", "unknown")
        org_id = org_info.get("id", "unknown")
        instance = org_info.get("instanceUrl", "unknown")
        report.append(f"- LMA org already authorized as **{alias}**")
        report.append(f"- Username: {username}")
        report.append(f"- Org ID: {org_id}")
        report.append(f"- Instance: {instance}")
    else:
        login_url = instance_url or DEFAULT_LMA_LOGIN_URL
        report.append(f"- LMA org '{alias}' is not yet authorized.")
        report.append(f"- Opening browser for login ({login_url})...")

        try:
            sf_cli.run_sf(
                f"org login web --alias {alias} --instance-url {login_url}",
                timeout=300,
                json_output=False,
            )
            report.append("- Browser login completed successfully.")
        except sf_cli.SfCliError as e:
            report.append(f"- Login failed: {e}")
            report.append(
                f"\nIf the browser did not open, run manually:\n"
                f"  ```\n"
                f"  sf org login web --alias {alias} "
                f"--instance-url {login_url}\n"
                f"  ```"
            )
            report.append("\n## STATUS: ACTION REQUIRED\n")
            report.append(
                "Login failed. Resolve the issue and call connect_lma again."
            )
            return "\n".join(report)

        org_info = _validate_org(alias)
        if not org_info:
            report.append("- Login appeared to succeed but org validation failed.")
            report.append("\n## STATUS: ACTION REQUIRED\n")
            report.append("Call connect_lma again to retry.")
            return "\n".join(report)

        username = org_info.get("username", "unknown")
        org_id = org_info.get("id", "unknown")
        instance = org_info.get("instanceUrl", "unknown")
        report.append(f"- Authorized as: {username}")
        report.append(f"- Org ID: {org_id}")
        report.append(f"- Instance: {instance}")

    # ── 2. Discover sfLma field model ───────────────────────────
    report.append("\n## sfLma Data Model Discovery\n")

    lma_fields = _describe_lma_objects(alias)

    has_fields = False
    for obj_name, fields in lma_fields.items():
        if fields:
            has_fields = True
            report.append(f"- **{obj_name}**: {len(fields)} fields discovered")
        else:
            report.append(
                f"- **{obj_name}**: Could not describe "
                f"(object may not exist in this org)"
            )

    if not has_fields:
        report.append(
            "\nWARNING: No sfLma objects could be described. "
            "This org may not be the LMA org, or the sfLma package "
            "is not installed. Verify the org and try again."
        )
        report.append("\n## STATUS: WARNING -- Verify this is the LMA org\n")
        return "\n".join(report)

    # ── 3. Store in state (if working_directory provided) ───────
    if working_dir_str:
        from pathlib import Path
        working_dir = Path(working_dir_str)
        existing = state.load_state(working_dir)
        if existing:
            state.update_state(
                working_dir,
                lma_org_alias=alias,
                lma_org_username=org_info.get("username", ""),
                lma_org_id=org_info.get("id", ""),
                lma_fields={k: v for k, v in lma_fields.items()},
            )
            report.append("\n## State\n")
            report.append(f"- LMA org info saved to state file")
            report.append(f"- sfLma field lists saved for downstream tools")
        else:
            report.append("\n## State\n")
            report.append(
                "- No existing state file found at working_directory. "
                "LMA connection info returned but not persisted. "
                "Call init_assessment first to create a state file, "
                "or omit working_directory to use this tool standalone."
            )

    # ── 4. Summary ──────────────────────────────────────────────
    report.append("\n---\n")
    report.append("## STATUS: READY\n")
    report.append(
        f"LMA org connected as '{alias}'. "
        f"sfLma data model discovered.\n\n"
        f"Next step: call **find_customer** with a customer name "
        f"to search the LMA org."
    )

    return "\n".join(report)
