"""Connector management commands — list, get, create, update, delete, test, activate, deactivate."""
from __future__ import annotations

from enum import IntEnum
from typing import Optional

import typer

from dattos_cli.client import ApiError
from dattos_cli.main import get_client, handle_api_error
from dattos_cli.output import is_tty, print_json
from dattos_cli.table import print_record, print_table


class ConnectorType(IntEnum):
    SqlServer = 1
    Oracle = 2
    PostgreSql = 3
    MySql = 4
    SapHana = 5
    Databricks = 6


_TYPE_NAMES = {t.value: t.name for t in ConnectorType}
_TYPE_LOOKUP = {t.name.lower(): t.value for t in ConnectorType}

VALID_TYPES = list(_TYPE_LOOKUP.keys())


def _fmt_type(v) -> str:
    return _TYPE_NAMES.get(v, str(v))


def _fmt_inactive(v) -> str:
    return "inactive" if v else "active"


CONNECTORS_COLUMNS = [
    ("ID", "Id", None),
    ("Name", "Name", None),
    ("Type", "ConnectorType", _fmt_type),
    ("Server", "Server", None),
    ("DB", "DatabaseName", None),
    ("Status", "IsInactive", _fmt_inactive),
]

app = typer.Typer(help="Manage Dattos connectors.", no_args_is_help=True)


@app.command("list")
def connectors_list(
    search: Optional[str] = typer.Option(None, "--search", "-s", help="Filter by name (partial match)."),
    page_size: int = typer.Option(50, "--page-size", help="Number of results per page."),
    no_cache: bool = typer.Option(False, "--no-cache", help="Bypass cache, fetch fresh data."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """List connectors in the organization."""
    client = get_client()
    params: dict = {"pageInfo.page": 0, "pageInfo.pageSize": page_size}
    if search:
        params["name"] = search
    try:
        resp = client.get("/api/Connector", params=params, cache=not no_cache, cache_ttl=300)
        data = resp.get("Data", resp) if isinstance(resp, dict) else resp
        if raw or not is_tty():
            print_json(data)
        else:
            print_table(data, CONNECTORS_COLUMNS, label="connectors")
    except ApiError as e:
        handle_api_error(e)


@app.command("get")
def connectors_get(
    connector_id: int = typer.Argument(help="Connector ID."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Get a connector by ID."""
    client = get_client()
    try:
        data = client.get(f"/api/Connector/{connector_id}")
        if raw or not is_tty():
            print_json(data)
        else:
            print_record(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("create")
def connectors_create(
    name: str = typer.Option(..., "--name", help="Connector name."),
    connector_type: str = typer.Option(..., "--type", help=f"Connector type: {', '.join(VALID_TYPES)}."),
    server: str = typer.Option("", "--server", help="Server hostname or address."),
    database: str = typer.Option("", "--database", help="Database name."),
    port: int = typer.Option(0, "--port", help="Port number."),
    username: str = typer.Option("", "--username", help="Username for authentication."),
    password: str = typer.Option("", "--password", help="Password for authentication."),
    connection_string: str = typer.Option("", "--connection-string", help="Full connection string (overrides individual fields)."),
    integrated_security: bool = typer.Option(False, "--integrated-security", help="Use Windows integrated security."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Create a new connector."""
    type_key = connector_type.lower()
    if type_key not in _TYPE_LOOKUP:
        from dattos_cli.output import print_error
        print_error("invalid_input", f"Unknown connector type: {connector_type}. Valid: {', '.join(VALID_TYPES)}", 1)
        raise typer.Exit(1)

    client = get_client()
    payload = {
        "Id": 0,
        "Name": name,
        "ConnectorType": _TYPE_LOOKUP[type_key],
        "Server": server,
        "DatabaseName": database,
        "Port": port,
        "Username": username,
        "Password": password,
        "ConnectionString": connection_string,
        "IntegratedSecurity": integrated_security,
        "IsInactive": False,
    }
    try:
        data = client.post("/api/Connector", json=payload)
        if raw or not is_tty():
            print_json(data)
        else:
            print_record(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("update")
def connectors_update(
    connector_id: int = typer.Argument(help="Connector ID to update."),
    name: Optional[str] = typer.Option(None, "--name", help="New connector name."),
    server: Optional[str] = typer.Option(None, "--server", help="New server hostname."),
    database: Optional[str] = typer.Option(None, "--database", help="New database name."),
    port: Optional[int] = typer.Option(None, "--port", help="New port number."),
    username: Optional[str] = typer.Option(None, "--username", help="New username."),
    password: Optional[str] = typer.Option(None, "--password", help="New password."),
    connection_string: Optional[str] = typer.Option(None, "--connection-string", help="New connection string."),
    integrated_security: Optional[bool] = typer.Option(None, "--integrated-security/--no-integrated-security", help="Toggle integrated security."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Update a connector's properties. Only provided fields are changed (read-modify-write)."""
    client = get_client()
    try:
        current = client.get(f"/api/Connector/{connector_id}")
    except ApiError as e:
        handle_api_error(e)
        return
    if name is not None:
        current["Name"] = name
    if server is not None:
        current["Server"] = server
    if database is not None:
        current["DatabaseName"] = database
    if port is not None:
        current["Port"] = port
    if username is not None:
        current["Username"] = username
    if password is not None:
        current["Password"] = password
    if connection_string is not None:
        current["ConnectionString"] = connection_string
    if integrated_security is not None:
        current["IntegratedSecurity"] = integrated_security
    try:
        data = client.put(f"/api/Connector/{connector_id}", json=current)
        if raw or not is_tty():
            print_json(data)
        else:
            print_record(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("delete")
def connectors_delete(
    connector_id: int = typer.Argument(help="Connector ID to delete."),
    yes: bool = typer.Option(False, "--yes", "-y", help="Confirm deletion without prompt."),
):
    """Delete a connector. Requires --yes to confirm (destructive, irreversible)."""
    if not yes:
        typer.echo("Error: deletion requires --yes flag to confirm.", err=True)
        raise typer.Exit(1)
    client = get_client()
    try:
        client.delete(f"/api/Connector/{connector_id}")
        print_json({"status": "deleted", "connectorId": connector_id})
    except ApiError as e:
        handle_api_error(e)


@app.command("test")
def connectors_test(
    connector_id: int = typer.Argument(help="Connector ID to test."),
):
    """Test a connector's connection by fetching it and validating via the API."""
    client = get_client()
    try:
        connector_data = client.get(f"/api/Connector/{connector_id}")
    except ApiError as e:
        handle_api_error(e)
        return
    try:
        result = client.post("/api/Connector/ValidConnection", json=connector_data)
        print_json(result)
    except ApiError as e:
        handle_api_error(e)


@app.command("activate")
def connectors_activate(
    connector_id: int = typer.Argument(help="Connector ID to activate."),
):
    """Activate a connector (set IsInactive=false)."""
    client = get_client()
    try:
        client.put("/api/Connector/Status/false", json=[connector_id])
        print_json({"status": "activated", "connectorId": connector_id})
    except ApiError as e:
        handle_api_error(e)


@app.command("deactivate")
def connectors_deactivate(
    connector_id: int = typer.Argument(help="Connector ID to deactivate."),
):
    """Deactivate a connector (set IsInactive=true)."""
    client = get_client()
    try:
        client.put("/api/Connector/Status/true", json=[connector_id])
        print_json({"status": "deactivated", "connectorId": connector_id})
    except ApiError as e:
        handle_api_error(e)
