#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script de exportación modular de esquema de base de datos
Exporta la estructura completa (CREATE TABLE) y los TRIGGERS asociados
de cada tabla de la base de datos 'pastelerias' en archivos .sql independientes.
"""

import os
import sys
import argparse
import configparser
from datetime import datetime
from collections import defaultdict
import pymysql
import pymysql.cursors

def load_default_config():
    """Lee configuración por defecto desde db_config.ini si existe."""
    config = {
        'host': '85.215.144.168',
        'port': 3306,
        'user': 'asesoft',
        'password': 'Pantera1',
        'database': 'pastelerias'
    }
    
    # Buscar db_config.ini en directorio actual y en raíz del proyecto
    search_paths = [
        os.path.join(os.path.dirname(__file__), '..', 'db_config.ini'),
        os.path.join(os.path.dirname(__file__), 'db_config.ini'),
        'db_config.ini'
    ]
    
    ini_path = None
    for p in search_paths:
        if os.path.exists(p):
            ini_path = os.path.abspath(p)
            break
            
    if ini_path:
        try:
            parser = configparser.ConfigParser()
            parser.read(ini_path, encoding='utf-8')
            if parser.has_section('Database'):
                sec = parser['Database']
                config['host'] = sec.get('Server', config['host'])
                config['port'] = sec.getint('Port', config['port'])
                config['user'] = sec.get('User_Name', config['user'])
                config['password'] = sec.get('Password', config['password'])
                config['database'] = sec.get('Database', config['database'])
        except Exception as e:
            print(f"[AVISO] No se pudo parsear {ini_path}: {e}")
            
    return config

def export_database_schema(args):
    """Ejecuta la exportación de tablas y triggers a archivos independientes."""
    start_time = datetime.now()
    output_dir = os.path.abspath(args.output_dir)
    os.makedirs(output_dir, exist_ok=True)

    print("=" * 70)
    print(" EXPORTADOR MODULAR DE ESQUEMA Y TRIGGERS")
    print(f" Servidor:  {args.host}:{args.port}")
    print(f" Base Datos: {args.database}")
    print(f" Directorio: {output_dir}")
    print("=" * 70)

    try:
        conn = pymysql.connect(
            host=args.host,
            port=args.port,
            user=args.user,
            password=args.password,
            database=args.database,
            charset='utf8mb4',
            cursorclass=pymysql.cursors.DictCursor
        )
    except Exception as e:
        print(f"[ERROR] Conexión fallida a MySQL/MariaDB: {e}")
        sys.exit(1)

    try:
        with conn.cursor() as cur:
            # 1. Obtener lista de tablas base
            cur.execute("SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'")
            table_rows = cur.fetchall()
            # El nombre de la columna en SHOW FULL TABLES suele ser Tables_in_<dbname>
            table_col_key = list(table_rows[0].keys())[0] if table_rows else None
            if not table_col_key:
                print("[INFO] No se encontraron tablas en la base de datos especificada.")
                return

            tables = sorted([r[table_col_key] for r in table_rows])
            print(f"\n[1/3] Encontradas {len(tables)} tablas base en '{args.database}'.")

            # 2. Obtener y agrupar todos los triggers de la base de datos
            print("[2/3] Consultando triggers y definiciones DDL asociadas...")
            cur.execute("SHOW TRIGGERS")
            all_triggers = cur.fetchall()
            print(f"      Encontrados {len(all_triggers)} triggers en total.")

            # Mapear triggers por tabla: { table_name: [trigger_dict, ...] }
            triggers_by_table = defaultdict(list)
            for trg in all_triggers:
                table_name = trg['Table']
                trigger_name = trg['Trigger']
                
                # Obtener la sentencia exacta de creación del trigger
                cur.execute(f"SHOW CREATE TRIGGER `{trigger_name}`")
                create_trg = cur.fetchone()
                sql_statement = create_trg.get('SQL Original Statement') or create_trg.get('Create Trigger')
                
                triggers_by_table[table_name].append({
                    'name': trigger_name,
                    'timing': trg.get('Timing'),
                    'event': trg.get('Event'),
                    'sql': sql_statement
                })

            # 3. Exportar cada tabla con sus triggers en su propio archivo .sql
            print(f"[3/3] Exportando archivos individuales en: {output_dir}\n")
            
            exported_count = 0
            total_triggers_exported = 0
            index_entries = []

            for idx, table in enumerate(tables, start=1):
                # Obtener CREATE TABLE DDL
                cur.execute(f"SHOW CREATE TABLE `{table}`")
                create_row = cur.fetchone()
                create_table_sql = create_row.get('Create Table', '')

                table_triggers = triggers_by_table.get(table, [])
                num_trg = len(table_triggers)
                total_triggers_exported += num_trg

                # Construir el contenido del archivo .sql
                now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                lines = []
                lines.append("-- " + "=" * 76)
                lines.append(f"-- Estructura de tabla y disparadores para `{table}`")
                lines.append(f"-- Base de datos: `{args.database}`")
                lines.append(f"-- Generado el:   {now_str}")
                lines.append(f"-- Triggers:      {num_trg}")
                lines.append("-- " + "=" * 76)
                lines.append("")
                lines.append("SET NAMES utf8mb4;")
                lines.append("SET FOREIGN_KEY_CHECKS = 0;")
                lines.append("")
                lines.append("--")
                lines.append(f"-- Estructura de la tabla `{table}`")
                lines.append("--")
                lines.append(f"DROP TABLE IF EXISTS `{table}`;")
                lines.append(create_table_sql.strip() + ";")
                lines.append("")

                if table_triggers:
                    lines.append("-- " + "-" * 76)
                    lines.append(f"-- Disparadores (Triggers) de la tabla `{table}`")
                    lines.append("-- " + "-" * 76)
                    lines.append("")
                    for t in table_triggers:
                        lines.append(f"-- Trigger: {t['name']} ({t['timing']} {t['event']})")
                        lines.append(f"DROP TRIGGER IF EXISTS `{t['name']}`;")
                        lines.append("DELIMITER ;;")
                        lines.append(t['sql'].strip() + " ;;")
                        lines.append("DELIMITER ;")
                        lines.append("")

                lines.append("SET FOREIGN_KEY_CHECKS = 1;")
                lines.append("")

                file_content = "\n".join(lines)
                table_file_path = os.path.join(output_dir, f"{table}.sql")
                
                with open(table_file_path, "w", encoding="utf-8") as f:
                    f.write(file_content)

                exported_count += 1
                trg_label = f"({num_trg} triggers)" if num_trg > 0 else ""
                print(f" [{idx:3d}/{len(tables):3d}] Exportada: {table:<40} {trg_label}")

                index_entries.append({
                    'table': table,
                    'triggers_count': num_trg,
                    'triggers_list': [t['name'] for t in table_triggers]
                })

            # 4. Generar archivo de índice README.md / _INDICE_TABLAS.md
            index_path = os.path.join(output_dir, "_INDICE_TABLAS.md")
            with open(index_path, "w", encoding="utf-8") as f:
                f.write(f"# Índice de Tablas y Triggers - Base de Datos `{args.database}`\n\n")
                f.write(f"- **Fecha de generación**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write(f"- **Servidor**: `{args.host}:{args.port}`\n")
                f.write(f"- **Total de tablas**: {exported_count}\n")
                f.write(f"- **Total de triggers**: {total_triggers_exported}\n\n")
                f.write("| # | Tabla | Archivo SQL | Triggers |\n")
                f.write("| :---: | :--- | :--- | :---: |\n")
                for i, ent in enumerate(index_entries, start=1):
                    trg_text = str(ent['triggers_count'])
                    if ent['triggers_count'] > 0:
                        trg_text = f"**{ent['triggers_count']}**"
                    f.write(f"| {i} | `{ent['table']}` | [{ent['table']}.sql](./{ent['table']}.sql) | {trg_text} |\n")

            # 5. Opcional: exportar Vistas si existen y se solicita o de forma complementaria
            if args.include_views:
                cur.execute("SHOW FULL TABLES WHERE Table_type = 'VIEW'")
                view_rows = cur.fetchall()
                if view_rows:
                    views_dir = os.path.join(output_dir, "vistas")
                    os.makedirs(views_dir, exist_ok=True)
                    v_col_key = list(view_rows[0].keys())[0]
                    views = sorted([r[v_col_key] for r in view_rows])
                    print(f"\nExportando {len(views)} vistas en '{views_dir}'...")
                    for v in views:
                        cur.execute(f"SHOW CREATE VIEW `{v}`")
                        cv_row = cur.fetchone()
                        v_sql = cv_row.get('Create View', '')
                        v_path = os.path.join(views_dir, f"{v}.sql")
                        with open(v_path, "w", encoding="utf-8") as vf:
                            vf.write(f"DROP VIEW IF EXISTS `{v}`;\n{v_sql};\n")

    finally:
        conn.close()

    elapsed = (datetime.now() - start_time).total_seconds()
    print("\n" + "=" * 70)
    print(" EXPORTACIÓN COMPLETADA CON ÉXITO")
    print(f" Tablas exportadas:   {exported_count}")
    print(f" Triggers incluidos:  {total_triggers_exported}")
    print(f" Directorio destino:  {output_dir}")
    print(f" Archivo índice:      {os.path.join(output_dir, '_INDICE_TABLAS.md')}")
    print(f" Tiempo transcurrido: {elapsed:.2f} segundos")
    print("=" * 70)

def main():
    default_cfg = load_default_config()

    parser = argparse.ArgumentParser(
        description="Exporta la estructura de todas las tablas de 'pastelerias' en archivos .sql independientes incluyendo sus triggers."
    )
    parser.add_argument("-H", "--host", default=default_cfg['host'], help=f"Host MySQL/MariaDB (defecto: {default_cfg['host']})")
    parser.add_argument("-P", "--port", type=int, default=default_cfg['port'], help=f"Puerto MySQL (defecto: {default_cfg['port']})")
    parser.add_argument("-u", "--user", default=default_cfg['user'], help=f"Usuario MySQL (defecto: {default_cfg['user']})")
    parser.add_argument("-p", "--password", default=default_cfg['password'], help="Contraseña MySQL")
    parser.add_argument("-d", "--database", default=default_cfg['database'], help=f"Nombre de la base de datos (defecto: {default_cfg['database']})")
    parser.add_argument("-o", "--output-dir", default=os.path.join(os.path.dirname(__file__), '..', 'sql', 'tablas'),
                        help="Directorio destino para los archivos .sql (defecto: sql/tablas)")
    parser.add_argument("--include-views", action="store_true", help="Exportar también las vistas en un subdirectorio 'vistas'")

    args = parser.parse_args()
    export_database_schema(args)

if __name__ == '__main__':
    main()
