import typer
import warnings
from rich.console import Console
from typing import Optional
from typing_extensions import Annotated

from cruxctl.command_groups.bigsnow.orgs import orgs
from cruxctl.command_groups.bigsnow.cdus import cdus
from cruxctl.command_groups.bigsnow.wrangles.wrangles import Wrangles
from cruxctl.command_groups.profile.profile import get_current_profile
from cruxctl.common.utils.api_utils import set_api_token, get_user_info_by_token
from cruxctl.common import constants
from cruxctl.common.utils.typer_utils import logger
from pathlib import Path

app = typer.Typer()

# BS
app.add_typer(orgs.app, name="orgs", help="orgs.")
app.add_typer(cdus.cdu, name="cdus", help="cdus.")

console = Console()
error_console = Console(stderr=True)
warnings.filterwarnings("ignore")

wrangles_app = typer.Typer(help="Wrangles management commands.")
app.add_typer(wrangles_app, name="wrangles", help="Wrangles-related commands.")


def _validate_admin_access():
    """
    Validate that the logged-in user has Crux Admin role.
    Raises typer.Exit if not authorized.
    """
    profile = get_current_profile()
    token = set_api_token(console, profile)

    if not token:
        logger.error("No API token found. Please run 'cruxctl auth login' first.")
        raise typer.Exit(1)

    try:
        user_profile = get_user_info_by_token(token, profile)
    except Exception as e:
        logger.error(f"Failed to get user information: {e}")
        logger.error("Unable to verify user authorization")
        raise typer.Exit(1)

    if not user_profile:
        logger.error("User Not Authorized")
        raise typer.Exit(1)

    user_roles = user_profile.get("roles", [])
    if (
        constants.CIAM_ROLE_CRUX_ADMIN not in user_roles
        and constants.CIAM_ROLE_CRUX_DATA_ENGINEER not in user_roles
    ):
        logger.error("You are not authorized to use bigsnow commands.")
        logger.error(
            f"Required role: {constants.CIAM_ROLE_CRUX_ADMIN} "
            f"or {constants.CIAM_ROLE_CRUX_DATA_ENGINEER}"
        )
        logger.error("Please contact your administrator for access.")
        raise typer.Exit(1)

    # If we get here, user is authorized
    logger.info(
        f"✓ Admin or Data Engineer access verified for user: {user_profile.get('email', 'unknown')}"
    )


@app.callback()
def entrypoint(
    ctx: typer.Context,
    instance: Annotated[
        str, typer.Option("--instance", "-i", help="Pass in the warehouse type")
    ] = None,
):
    """
    Bigsnow command group callback.
    Validates admin access before allowing any bigsnow commands to execute.
    """
    # Validate admin access before any bigsnow command
    _validate_admin_access()

    print(f"Passed instance is: {instance}")
    ctx.obj = {
        "instance": instance,
    }


@wrangles_app.command("list-all")
def list_all_wrangles(
    cdu_id: Optional[str] = typer.Option(None, "--cdu_id", "-cdu_id", help="CDU ID"),
):
    handler = Wrangles()
    handler.list_all_wrangles(cdu_id)


@wrangles_app.command("list")
def list_wrangle(
    cdu_id: Annotated[
        str, typer.Option("--cdu_id", "-cdu_id", help="Database type")
    ] = None,
    wrangle_name: Annotated[
        str, typer.Option("--wrangle_name", "-wrangle_name", help="Database type")
    ] = None,
    output_file: Annotated[
        Path, typer.Option("--output_file", "-output_file", help="Output file path")
    ] = None,
):
    handler = Wrangles()
    handler.list_wrangle(cdu_id, wrangle_name, output_file)


@wrangles_app.command("schema")
def schema_wrangles(
    cdu_id: Annotated[str, typer.Option("--cdu_id", "-cdu_id", help="CDU ID")] = None,
    wrangle_name: Annotated[
        str, typer.Option("--wrangle_name", "-wrangle_name", help="Database type")
    ] = None,
):
    handler = Wrangles()
    handler.schema_wrangles(cdu_id, wrangle_name)


@wrangles_app.command("modify")
def modify_wrangles(
    cdu_id: Annotated[str, typer.Option("--cdu_id", "-cdu_id", help="CDU ID")] = None,
    dw_type: Annotated[
        str,
        typer.Option("--dw_type", "-dw_type", help="Data warehouse type (BQ or SF)"),
    ] = None,
    sql_file: Annotated[
        Path,
        typer.Option(
            "--sql_file",
            "-sql_file",
            exists=True,
            readable=True,
            help="Path to SQL file",
        ),
    ] = None,
    wrangle_name: Annotated[
        str, typer.Option("--wrangle_name", "-wrangle_name", help="Name of the wrangle")
    ] = None,
    legacy_id: Annotated[
        str,
        typer.Option(
            "--legacy_id", "-legacy_id", help="Legacy ID for view naming (REQUIRED)"
        ),
    ] = None,
):
    """
    Create or update a wrangle with support for both Snowflake and BigQuery
    Always creates/updates in PROD environment.
    """
    sql = sql_file.read_text()
    handler = Wrangles()
    handler.modify_wrangles(cdu_id, dw_type, sql, wrangle_name, legacy_id)


@wrangles_app.command("validate")
def validate_sql(
    dw_type: Annotated[
        str, typer.Option("--dw_type", "-dw_type", help="Data warehouse type: BQ or SF")
    ] = None,
    sql_file: Annotated[
        Path,
        typer.Option(
            "--sql_file",
            "-sql_file",
            exists=True,
            readable=True,
            help="Path to SQL file",
        ),
    ] = None,
    cdu_id: Annotated[
        Optional[str],
        typer.Option(
            "--cdu_id", "-cdu_id", help="CDU ID (Optional - to create UAT view)"
        ),
    ] = None,
    wrangle_name: Annotated[
        Optional[str],
        typer.Option(
            "--wrangle_name",
            "-wrangle_name",
            help="Wrangle name (Optional - to create UAT view)",
        ),
    ] = None,
    legacy_id: Annotated[
        Optional[str],
        typer.Option(
            "--legacy_id",
            "-legacy_id",
            help="Legacy ID (Optional - to create UAT view)",
        ),
    ] = None,
):
    """
    Validate SQL file - checks syntax, row count, and column information.
    Optionally create a view in UAT if CDU parameters are provided.

    Examples:
        # Validate only
        cruxctl bigsnow wrangles validate --dw_type BQ --sql_file query.sql

        # Validate and create UAT view
        cruxctl bigsnow wrangles validate --dw_type BQ --sql_file query.sql \\
          --cdu_id Cx02154 --wrangle_name MY_WRANGLE --legacy_id ABC123
    """
    handler = Wrangles()
    handler.validate_sql(dw_type, str(sql_file), cdu_id, wrangle_name, legacy_id)
