"""
cli.py
------
hanaflow CLI — entry point registered as the `hanaflow` command.

Usage examples
--------------
  # Minimal — reads credentials from .env
  hanaflow upload --file sales_data.csv

  # Override credentials inline
  hanaflow upload --file data.xlsx \\
      --host my-hana.hanacloud.ondemand.com \\
      --port 443 --user DBADMIN --password secret

  # Custom schema / table names + replace existing table
  hanaflow upload --file orders.csv \\
      --schema MY_SCHEMA --table ORDERS_2024 --replace

  # Check HANA connectivity
  hanaflow ping --host ... --port 443 --user ... --password ...

  # Generate an LLM summary of a dataset
  hanaflow summary --file sales_data.csv

  # Ask a natural language question about a dataset
  hanaflow ask --file sales_data.csv --question "What is the average salary by city?"

  # Verbose debug logging
  hanaflow --verbose upload --file data.csv
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import Optional

import typer
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TextColumn

from hanaflow.config import ConnectorConfig
from hanaflow.connector import HANAConnector
from hanaflow.ingestion.reader import read_file
from hanaflow.ingestion.uploader import upload
from hanaflow.utils import print_error, print_info, print_success, setup_logging

console = Console()

app = typer.Typer(
    name="hanaflow",
    help="Upload datasets to SAP HANA, expose REST APIs, and query with LLM.",
    add_completion=False,
    no_args_is_help=True,
)

# ---------------------------------------------------------------------------
# Global options callback
# ---------------------------------------------------------------------------

_verbose_state: dict = {"value": False}


@app.callback()
def global_options(
    verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
) -> None:
    _verbose_state["value"] = verbose
    setup_logging(verbose=verbose)


# ---------------------------------------------------------------------------
# Shared connection options (reused across commands)
# ---------------------------------------------------------------------------

def _build_config(
    host: Optional[str],
    port: Optional[int],
    user: Optional[str],
    password: Optional[str],
    encrypt: Optional[bool],
) -> ConnectorConfig:
    """
    Build ConnectorConfig from CLI flags, falling back to .env / environment vars.
    CLI flags take precedence over environment variables.
    """
    cfg = ConnectorConfig()   # loads from env first
    if host     is not None: cfg.host     = host
    if port     is not None: cfg.port     = port
    if user     is not None: cfg.user     = user
    if password is not None: cfg.password = password
    if encrypt  is not None: cfg.encrypt  = encrypt
    return cfg


# ---------------------------------------------------------------------------
# `hanaflow upload` command
# ---------------------------------------------------------------------------

@app.command()
def upload_cmd(
    file: Path = typer.Option(
        ...,
        "--file", "-f",
        help="Path to the data file (.csv, .xlsx, .xls, .json, .parquet).",
        exists=True,
        file_okay=True,
        dir_okay=False,
        readable=True,
    ),
    host: Optional[str] = typer.Option(None, "--host",     help="SAP HANA host."),
    port: Optional[int] = typer.Option(None, "--port",     help="SAP HANA port (default 443)."),
    user: Optional[str] = typer.Option(None, "--user",     help="Database user."),
    password: Optional[str] = typer.Option(
        None, "--password", envvar="HANA_PASSWORD",
        help="Database password (also reads HANA_PASSWORD env var).",
    ),
    encrypt: Optional[bool] = typer.Option(
        None, "--encrypt/--no-encrypt",
        help="Enable TLS (default True for HANA Cloud).",
    ),
    schema: Optional[str] = typer.Option(
        None, "--schema", "-s",
        help="Override auto-derived HANA schema name.",
    ),
    table: Optional[str] = typer.Option(
        None, "--table", "-t",
        help="Override auto-derived HANA table name.",
    ),
    replace: bool = typer.Option(
        False, "--replace",
        help="Drop and recreate the table if it already exists.",
    ),
    batch_size: int = typer.Option(
        1_000, "--batch-size",
        help="Rows per INSERT batch (default 1000).",
    ),
    sheet: str = typer.Option(
        "0", "--sheet",
        help="Excel sheet name or 0-based index (default 0).",
    ),
) -> None:
    """
    Upload a local data file to SAP HANA.

    \b
    Steps performed:
      1. Read the file into a DataFrame (CSV / Excel / JSON / Parquet)
      2. Connect to SAP HANA using hdbcli
      3. CREATE SCHEMA (skip if exists)
      4. CREATE TABLE  (infer column types automatically)
      5. INSERT all rows via hdbcli executemany()
      6. Print a success summary with schema, table, and row count
    """
    # --- Resolve sheet_name for Excel -------------------------------------
    sheet_name: str | int = int(sheet) if sheet.isdigit() else sheet

    # --- Build config -----------------------------------------------------
    try:
        cfg = _build_config(host, port, user, password, encrypt)
        cfg.validate()
    except ValueError as exc:
        print_error(str(exc))
        raise typer.Exit(code=1)

    # --- Step 1: Read file ------------------------------------------------
    print_info(f"Reading file: {file}")
    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        transient=True,
    ) as progress:
        task = progress.add_task("Reading data …", total=None)
        try:
            df = read_file(file, sheet_name=sheet_name)
        except (FileNotFoundError, ValueError) as exc:
            print_error(str(exc))
            raise typer.Exit(code=1)
        progress.update(task, description=f"Read {len(df):,} rows × {len(df.columns)} columns")

    print_info(f"Loaded {len(df):,} rows, {len(df.columns)} columns.")

    # --- Steps 2-5: Connect and upload ------------------------------------
    connector = HANAConnector(cfg)

    try:
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            transient=True,
        ) as progress:
            # Connect
            conn_task = progress.add_task("Connecting to SAP HANA …", total=None)
            try:
                connection = connector.connect()
            except Exception as exc:
                print_error(f"Cannot connect to SAP HANA: {exc}")
                raise typer.Exit(code=1)
            progress.update(conn_task, description="Connected ✓")

            # Upload
            up_task = progress.add_task("Uploading data …", total=None)
            try:
                result = upload(
                    connection  = connection,
                    df          = df,
                    file_path   = file,
                    schema_name = schema,
                    table_name  = table,
                    replace     = replace,
                    batch_size  = batch_size,
                )
            except RuntimeError as exc:
                print_error(str(exc))
                raise typer.Exit(code=1)
            except Exception as exc:
                print_error(f"Upload failed: {exc}")
                if _verbose_state["value"]:
                    import traceback
                    traceback.print_exc()
                raise typer.Exit(code=1)
            progress.update(up_task, description="Upload complete ✓")

    finally:
        connector.disconnect()

    # --- Step 6: Success summary ------------------------------------------
    print_success(
        schema  = result.schema_name,
        table   = result.table_name,
        rows    = result.rows_inserted,
        columns = result.columns,
    )


# ---------------------------------------------------------------------------
# `hanaflow ping` command — quick connectivity check
# ---------------------------------------------------------------------------

@app.command()
def ping(
    host: Optional[str] = typer.Option(None, "--host"),
    port: Optional[int] = typer.Option(None, "--port"),
    user: Optional[str] = typer.Option(None, "--user"),
    password: Optional[str] = typer.Option(None, "--password", envvar="HANA_PASSWORD"),
    encrypt: Optional[bool] = typer.Option(None, "--encrypt/--no-encrypt"),
) -> None:
    """Test connectivity to SAP HANA and print the server version."""
    try:
        cfg = _build_config(host, port, user, password, encrypt)
        cfg.validate()
    except ValueError as exc:
        print_error(str(exc))
        raise typer.Exit(code=1)

    connector = HANAConnector(cfg)
    try:
        connector.connect()
        version = connector.test_connection()
        typer.echo(typer.style(f"✓ Connected to SAP HANA {version}", fg=typer.colors.GREEN))
    except Exception as exc:
        print_error(f"Connection failed: {exc}")
        raise typer.Exit(code=1)
    finally:
        connector.disconnect()


# ---------------------------------------------------------------------------
# `hanaflow summary` command — LLM dataset summary
# ---------------------------------------------------------------------------

@app.command()
def summary(
    file: Path = typer.Option(
        ...,
        "--file", "-f",
        help="Path to the data file (.csv, .xlsx, .xls, .json, .parquet).",
        exists=True,
        file_okay=True,
        dir_okay=False,
        readable=True,
    ),
) -> None:
    """
    Generate a plain-English LLM summary of your dataset.

    \b
    Covers:
      - What the dataset is about
      - Key columns and their meaning
      - Data quality issues (nulls, duplicates)
      - Potential ML use cases
      - One quick insight from the data
    """
    from hanaflow.llm.service import LLMService

    print_info(f"Loading dataset: {file}")

    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        transient=True,
    ) as progress:
        # Load data
        load_task = progress.add_task("Reading data …", total=None)
        try:
            service = LLMService(str(file))
            service.load_transform_data()
            service.gather_info()
        except Exception as exc:
            print_error(f"Failed to load data: {exc}")
            raise typer.Exit(code=1)
        progress.update(load_task, description=f"Loaded {service.shape[0]:,} rows ✓")

        # Generate summary
        llm_task = progress.add_task("Generating LLM summary …", total=None)
        try:
            result = service.generate_summary()
        except Exception as exc:
            print_error(f"LLM summary failed: {exc}")
            if _verbose_state["value"]:
                import traceback
                traceback.print_exc()
            raise typer.Exit(code=1)
        progress.update(llm_task, description="Summary ready ✓")

    # Print the result as rich Markdown
    console.print(
        Panel(
            Markdown(result),
            title=f"[bold cyan]Dataset Summary — {file.name}[/bold cyan]",
            border_style="cyan",
            padding=(1, 2),
        )
    )


# ---------------------------------------------------------------------------
# `hanaflow ask` command — ask any question about the dataset
# ---------------------------------------------------------------------------

@app.command()
def ask(
    file: Path = typer.Option(
        ...,
        "--file", "-f",
        help="Path to the data file to query.",
        exists=True,
        file_okay=True,
        dir_okay=False,
        readable=True,
    ),
    question: str = typer.Option(
        ...,
        "--question", "-q",
        help='Natural language question about the dataset e.g. "What is the average salary?"',
    ),
) -> None:
    """
    Ask any natural language question about your dataset using LLM.

    \b
    Examples:
      hanaflow ask -f sales.csv -q "What is the average salary by city?"
      hanaflow ask -f sales.csv -q "Which column has the most null values?"
      hanaflow ask -f sales.csv -q "Is this dataset good for classification?"
    """
    from hanaflow.llm.llm_service import LLMService

    print_info(f"Loading dataset: {file}")

    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        transient=True,
    ) as progress:
        # Load data
        load_task = progress.add_task("Reading data …", total=None)
        try:
            service = LLMService(str(file))
            service.load_transform_data()
            service.gather_info()
        except Exception as exc:
            print_error(f"Failed to load data: {exc}")
            raise typer.Exit(code=1)
        progress.update(load_task, description=f"Loaded {service.shape[0]:,} rows ✓")

        # Ask LLM
        ask_task = progress.add_task("Thinking …", total=None)
        try:
            result = service.ask(question)
        except Exception as exc:
            print_error(f"LLM query failed: {exc}")
            if _verbose_state["value"]:
                import traceback
                traceback.print_exc()
            raise typer.Exit(code=1)
        progress.update(ask_task, description="Answer ready ✓")

    # Print question and answer
    console.print(
        Panel(
            f"[bold yellow]Q:[/bold yellow] {question}",
            border_style="yellow",
            padding=(0, 2),
        )
    )
    console.print(
        Panel(
            Markdown(result),
            title="[bold green]Answer[/bold green]",
            border_style="green",
            padding=(1, 2),
        )
    )


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    app()
