#!/usr/bin/env python3
"""MS SQL client tool for ScadaLink test infrastructure."""

import argparse
import sys

import pymssql


DEFAULT_HOST = "localhost"
DEFAULT_PORT = 1433
DEFAULT_USER = "sa"
DEFAULT_PASSWORD = "ScadaLink_Dev1#"
EXPECTED_DBS = ["ScadaLinkConfig", "ScadaLinkMachineData"]


def get_connection(args, database=None):
    """Create and return a database connection."""
    return pymssql.connect(
        server=args.host,
        port=args.port,
        user=args.user,
        password=args.password,
        database=database or "master",
    )


def cmd_check(args):
    """Connect and list databases, verify expected DBs exist."""
    try:
        conn = get_connection(args)
        cursor = conn.cursor()
        cursor.execute("SELECT name FROM sys.databases ORDER BY name")
        databases = [row[0] for row in cursor.fetchall()]

        print(f"Connected to: {args.host}:{args.port}")
        print(f"Databases ({len(databases)}):")
        for db in databases:
            marker = " <-- expected" if db in EXPECTED_DBS else ""
            print(f"  {db}{marker}")

        missing = [db for db in EXPECTED_DBS if db not in databases]
        if missing:
            print(f"\nMissing expected databases: {', '.join(missing)}")
            print("Run: python infra/tools/mssql_tool.py setup --script infra/mssql/setup.sql")
            sys.exit(1)
        else:
            print("\nAll expected databases present.")

        cursor.close()
        conn.close()
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


def cmd_setup(args):
    """Execute a SQL script file."""
    try:
        with open(args.script, "r") as f:
            sql = f.read()
    except FileNotFoundError:
        print(f"Error: script not found: {args.script}", file=sys.stderr)
        sys.exit(1)

    try:
        conn = get_connection(args)
        conn.autocommit(True)
        cursor = conn.cursor()

        # Split on GO statements (SQL Server batch separator)
        batches = []
        current = []
        for line in sql.splitlines():
            if line.strip().upper() == "GO":
                if current:
                    batches.append("\n".join(current))
                    current = []
            else:
                current.append(line)
        if current:
            batches.append("\n".join(current))

        for i, batch in enumerate(batches, 1):
            batch = batch.strip()
            if not batch:
                continue
            cursor.execute(batch)
            print(f"  Batch {i} executed.")

        print(f"\nScript completed: {args.script} ({len(batches)} batches)")
        cursor.close()
        conn.close()
    except Exception as e:
        print(f"Error executing script: {e}", file=sys.stderr)
        sys.exit(1)


def cmd_query(args):
    """Run an ad-hoc SQL query and print results."""
    try:
        conn = get_connection(args, database=args.database)
        cursor = conn.cursor()
        cursor.execute(args.sql)

        if cursor.description:
            columns = [desc[0] for desc in cursor.description]
            rows = cursor.fetchall()

            # Calculate column widths
            widths = [len(c) for c in columns]
            for row in rows:
                for i, val in enumerate(row):
                    widths[i] = max(widths[i], len(str(val)))

            # Print header
            header = "  ".join(c.ljust(w) for c, w in zip(columns, widths))
            print(header)
            print("  ".join("-" * w for w in widths))

            # Print rows
            for row in rows:
                print("  ".join(str(v).ljust(w) for v, w in zip(row, widths)))

            print(f"\n({len(rows)} rows)")
        else:
            conn.commit()
            print(f"Query executed. Rows affected: {cursor.rowcount}")

        cursor.close()
        conn.close()
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


def cmd_tables(args):
    """List all tables in a database."""
    try:
        conn = get_connection(args, database=args.database)
        cursor = conn.cursor()
        cursor.execute("""
            SELECT s.name AS [schema], t.name AS [table],
                   SUM(p.rows) AS [rows]
            FROM sys.tables t
            JOIN sys.schemas s ON t.schema_id = s.schema_id
            JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0, 1)
            GROUP BY s.name, t.name
            ORDER BY s.name, t.name
        """)
        rows = cursor.fetchall()

        if not rows:
            print(f"No tables in {args.database}.")
        else:
            print(f"Tables in {args.database}:")
            print(f"{'Schema':<15} {'Table':<40} {'Rows':<10}")
            print("-" * 65)
            for schema, table, count in rows:
                print(f"{schema:<15} {table:<40} {count:<10}")
            print(f"\n({len(rows)} tables)")

        cursor.close()
        conn.close()
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="MS SQL client tool for ScadaLink test infrastructure")
    parser.add_argument("--host", default=DEFAULT_HOST, help=f"SQL Server host (default: {DEFAULT_HOST})")
    parser.add_argument("--port", type=int, default=DEFAULT_PORT, help=f"Port (default: {DEFAULT_PORT})")
    parser.add_argument("--user", default=DEFAULT_USER, help=f"Username (default: {DEFAULT_USER})")
    parser.add_argument("--password", default=DEFAULT_PASSWORD, help=f"Password (default: {DEFAULT_PASSWORD})")

    sub = parser.add_subparsers(dest="command", required=True)

    sub.add_parser("check", help="Connect and verify expected databases")

    setup_p = sub.add_parser("setup", help="Execute a SQL script")
    setup_p.add_argument("--script", required=True, help="Path to SQL script file")

    query_p = sub.add_parser("query", help="Run an ad-hoc SQL query")
    query_p.add_argument("--database", required=True, help="Database name")
    query_p.add_argument("--sql", required=True, help="SQL query to execute")

    tables_p = sub.add_parser("tables", help="List all tables in a database")
    tables_p.add_argument("--database", required=True, help="Database name")

    args = parser.parse_args()

    commands = {
        "check": cmd_check,
        "setup": cmd_setup,
        "query": cmd_query,
        "tables": cmd_tables,
    }

    commands[args.command](args)


if __name__ == "__main__":
    main()
