#!/usr/bin/env python3
"""Automated Metabase setup for Nexus Autoparts KPIs.

Performs first-time setup if needed, then creates:
  - PostgreSQL database connection (master + tenant template)
  - Collection "Nexus KPIs"
  - Pre-built questions (cards) for common refaccionaria metrics
  - Dashboard grouping those cards

Usage:
    export METABASE_URL=http://localhost:3000
    export METABASE_ADMIN_EMAIL=admin@nexus.local
    export METABASE_ADMIN_PASS=changeme123
    export MASTER_DB_URL=postgresql://nexus:pass@localhost/nexus_autoparts
    python3 scripts/setup_metabase.py
"""

import os
import sys
import json
import time
import requests

METABASE_URL = os.environ.get('METABASE_URL', 'http://localhost:3000').rstrip('/')
ADMIN_EMAIL = os.environ.get('METABASE_ADMIN_EMAIL', 'admin@nexus.local')
ADMIN_PASS = os.environ.get('METABASE_ADMIN_PASS', '')
MASTER_DB_URL = os.environ.get('MASTER_DB_URL', '')

DB_CONFIG_PATH = os.path.expanduser('~/.nexus_metabase_config.json')


def _get(url, session=None):
    headers = {}
    if session:
        headers['X-Metabase-Session'] = session
    r = requests.get(url, headers=headers)
    return r


def _post(url, data, session=None):
    headers = {'Content-Type': 'application/json'}
    if session:
        headers['X-Metabase-Session'] = session
    r = requests.post(url, headers=headers, json=data)
    return r


def get_setup_token():
    r = _get(f"{METABASE_URL}/api/session/properties")
    return r.json().get('setup-token')


def do_setup(token):
    """Create first admin user and initial DB connection."""
    if not ADMIN_PASS:
        print("ERROR: METABASE_ADMIN_PASS is required for first-time setup.")
        sys.exit(1)

    # Parse DB connection
    db_name = 'nexus_autoparts'
    db_user = 'nexus'
    db_pass = ''
    if MASTER_DB_URL:
        # postgresql://user:pass@host/db
        rest = MASTER_DB_URL.replace('postgresql://', '')
        if '@' in rest:
            auth, host_db = rest.split('@', 1)
            if ':' in auth:
                db_user, db_pass = auth.split(':', 1)
            else:
                db_user = auth
            if '/' in host_db:
                host_port, db_name = host_db.split('/', 1)
            else:
                host_port = host_db
            host = host_port.split(':')[0]
        else:
            host = 'localhost'
    else:
        host = 'host.docker.internal'

    payload = {
        'token': token,
        'user': {
            'first_name': 'Admin',
            'last_name': 'Nexus',
            'email': ADMIN_EMAIL,
            'site_name': 'Nexus Autoparts',
            'password': ADMIN_PASS,
        },
        'prefs': {
            'site_name': 'Nexus Autoparts',
            'site_locale': 'es',
            'allow_tracking': False,
        },
        'database': {
            'engine': 'postgres',
            'name': 'Nexus Master DB',
            'details': {
                'host': host,
                'port': 5432,
                'dbname': db_name,
                'user': db_user,
                'password': db_pass,
                'ssl': False,
                'tunnel-enabled': False,
            },
            'auto_run_queries': True,
            'is_full_sync': True,
            'is_on_demand': False,
        }
    }

    r = _post(f"{METABASE_URL}/api/setup", payload)
    if r.status_code not in (200, 201):
        print(f"Setup failed: {r.status_code} {r.text}")
        sys.exit(1)

    data = r.json()
    session_id = data.get('id')
    print(f"Setup complete. Admin user created: {ADMIN_EMAIL}")
    return session_id


def login():
    """Login existing user."""
    r = _post(f"{METABASE_URL}/api/session", {
        'username': ADMIN_EMAIL,
        'password': ADMIN_PASS,
    })
    if r.status_code != 200:
        print(f"Login failed: {r.status_code} {r.text}")
        return None
    return r.json().get('id')


def get_or_create_collection(session, name="Nexus KPIs"):
    """Get existing collection or create new."""
    r = _get(f"{METABASE_URL}/api/collection", session)
    for c in r.json():
        if c.get('name') == name:
            return c['id']

    r = _post(f"{METABASE_URL}/api/collection", {
        'name': name,
        'color': '#509EE3',
        'description': 'Dashboards y métricas para Nexus Autoparts'
    }, session)
    return r.json()['id']


def create_question(session, collection_id, name, sql, display='table', visualization_settings=None):
    """Create a native SQL question (card)."""
    payload = {
        'name': name,
        'dataset_query': {
            'type': 'native',
            'native': {
                'query': sql,
                'template-tags': {},
            },
            'database': None,  # Will be set from first available DB
        },
        'display': display,
        'collection_id': collection_id,
        'visualization_settings': visualization_settings or {},
    }
    # Find first available database
    dbs = _get(f"{METABASE_URL}/api/database", session).json()
    if 'data' in dbs and dbs['data']:
        payload['dataset_query']['database'] = dbs['data'][0]['id']
    else:
        print("WARNING: No databases found in Metabase. Skipping question creation.")
        return None

    r = _post(f"{METABASE_URL}/api/card", payload, session)
    if r.status_code in (200, 201):
        return r.json()['id']
    print(f"Card creation failed ({name}): {r.status_code} {r.text[:200]}")
    return None


def create_dashboard(session, collection_id, name):
    """Create a dashboard."""
    r = _post(f"{METABASE_URL}/api/dashboard", {
        'name': name,
        'collection_id': collection_id,
        'description': 'KPIs principales de la refaccionaria',
    }, session)
    if r.status_code in (200, 201):
        return r.json()['id']
    print(f"Dashboard creation failed: {r.status_code} {r.text[:200]}")
    return None


def add_card_to_dashboard(session, dashboard_id, card_id, row, col, size_x=6, size_y=4):
    """Add a card to a dashboard grid."""
    payload = {
        'cardId': card_id,
        'row': row,
        'col': col,
        'sizeX': size_x,
        'sizeY': size_y,
    }
    r = _post(f"{METABASE_URL}/api/dashboard/{dashboard_id}/cards", payload, session)
    return r.status_code in (200, 201)


def main():
    print("Nexus Autoparts — Metabase Setup")
    print("=" * 50)

    # Verify Metabase is reachable
    try:
        health = requests.get(f"{METABASE_URL}/api/health").json()
        if health.get('status') != 'ok':
            print("ERROR: Metabase is not ready.")
            sys.exit(1)
    except Exception as e:
        print(f"ERROR: Cannot reach Metabase: {e}")
        sys.exit(1)

    # Determine if first-time setup is needed
    token = get_setup_token()
    session = None
    if token:
        print("First-time setup detected...")
        session = do_setup(token)
    else:
        print("Metabase already set up. Logging in...")
        if not ADMIN_PASS:
            print("ERROR: METABASE_ADMIN_PASS required to login.")
            sys.exit(1)
        session = login()

    if not session:
        print("ERROR: Could not obtain Metabase session.")
        sys.exit(1)

    # Save config
    config = {
        'metabase_url': METABASE_URL,
        'admin_email': ADMIN_EMAIL,
        'session_id': session,
    }
    with open(DB_CONFIG_PATH, 'w') as f:
        json.dump(config, f)
    os.chmod(DB_CONFIG_PATH, 0o600)

    # Create collection
    coll_id = get_or_create_collection(session)
    print(f"Collection ID: {coll_id}")

    # Create questions
    questions = []

    q1 = create_question(session, coll_id,
        "Ventas por día (últimos 30 días)",
        """
SELECT DATE(created_at) as fecha, COUNT(*) as ventas, SUM(total) as total
FROM sales
WHERE status = 'completed'
  AND created_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY fecha
ORDER BY fecha DESC;
        """,
        display='line',
        visualization_settings={"graph.dimensions":["fecha"],"graph.metrics":["ventas","total"]}
    )
    if q1: questions.append((q1, 0, 0, 6, 4))

    q2 = create_question(session, coll_id,
        "Top 10 productos vendidos",
        """
SELECT si.part_number, si.name, SUM(si.quantity) as cantidad, SUM(si.subtotal) as revenue
FROM sale_items si
JOIN sales s ON si.sale_id = s.id
WHERE s.status = 'completed'
GROUP BY si.part_number, si.name
ORDER BY cantidad DESC
LIMIT 10;
        """,
        display='bar'
    )
    if q2: questions.append((q2, 0, 6, 6, 4))

    q3 = create_question(session, coll_id,
        "Stock bajo (reorder alerts abiertas)",
        """
SELECT i.part_number, i.name, ra.stock_at_alert, ra.threshold, b.name as branch
FROM reorder_alerts ra
JOIN inventory i ON ra.inventory_id = i.id
LEFT JOIN branches b ON ra.branch_id = b.id
WHERE ra.status = 'open'
ORDER BY ra.stock_at_alert ASC;
        """
    )
    if q3: questions.append((q3, 4, 0, 6, 4))

    q4 = create_question(session, coll_id,
        "Ventas por sucursal (este mes)",
        """
SELECT b.name as sucursal, COUNT(*) as ventas, SUM(s.total) as total
FROM sales s
LEFT JOIN branches b ON s.branch_id = b.id
WHERE s.status = 'completed'
  AND s.created_at >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY sucursal
ORDER BY total DESC;
        """,
        display='pie'
    )
    if q4: questions.append((q4, 4, 6, 6, 4))

    q5 = create_question(session, coll_id,
        "Clientes con más compras",
        """
SELECT c.name, COUNT(*) as compras, SUM(s.total) as total
FROM sales s
JOIN customers c ON s.customer_id = c.id
WHERE s.status = 'completed'
GROUP BY c.name
ORDER BY total DESC
LIMIT 10;
        """
    )
    if q5: questions.append((q5, 8, 0, 6, 4))

    q6 = create_question(session, coll_id,
        "Margen de ganancia por producto",
        """
SELECT si.name,
       SUM(si.unit_cost * si.quantity) as costo_total,
       SUM(si.subtotal) as venta_total,
       ROUND(((SUM(si.subtotal) - SUM(si.unit_cost * si.quantity)) / NULLIF(SUM(si.subtotal), 0)) * 100, 2) as margen_pct
FROM sale_items si
JOIN sales s ON si.sale_id = s.id
WHERE s.status = 'completed'
GROUP BY si.name
HAVING SUM(si.subtotal) > 0
ORDER BY margen_pct DESC
LIMIT 10;
        """
    )
    if q6: questions.append((q6, 8, 6, 6, 4))

    # Create dashboard
    if questions:
        dash_id = create_dashboard(session, coll_id, "Nexus KPIs — Panel Principal")
        if dash_id:
            for card_id, row, col, sx, sy in questions:
                add_card_to_dashboard(session, dash_id, card_id, row, col, sx, sy)
            print(f"Dashboard created: {METABASE_URL}/dashboard/{dash_id}")
        else:
            print("Dashboard creation skipped.")
    else:
        print("No questions created (no database connected yet).")

    print("\nDone. Access Metabase at:", METABASE_URL)
    print(f"Admin email: {ADMIN_EMAIL}")
    print(f"Config saved to: {DB_CONFIG_PATH}")


if __name__ == '__main__':
    main()
