import os
import pyodbc
import adodbapi
import traceback
from dotenv import load_dotenv
import mail
import datetime

load_dotenv()

MAIN_DIR = os.getcwd()
LOG_DIR = os.path.join(MAIN_DIR, 'Logs')
os.makedirs(LOG_DIR, exist_ok=True)
logfile_name = f"SDF_importer_log_{datetime.datetime.now().strftime('%Y-%m-%d')}.txt"
logfile_path = os.path.join(LOG_DIR, logfile_name)

process = 'MSSQL_to_SDF_Import'
mssql_cursor_global = None


def write_log(line):
    timestamp = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    log_entry = f'{line}\n------------------------------{timestamp}------------------------------'
    print(line)
    with open(logfile_path, 'a', encoding='utf-8') as f:
        f.write(log_entry + '\n')


def write_log_summary(table, inserted, skipped, errors, inserted_rows):
    """Zusammenfassung pro Tabelle in DB schreiben"""
    global mssql_cursor_global
    if not mssql_cursor_global:
        return
    try:
        if inserted == 0 and errors == 0:
            message = '-'
        else:
            message = f'{inserted} eingefügt, {skipped} übersprungen, {errors} Fehler'
            if inserted_rows:
                message += ' | ' + '; '.join(inserted_rows[:5])
        full_message = f'Tabelle {table}: {message}'
        mssql_cursor_global.execute(
            'INSERT INTO logs (timestamp, message, process) VALUES (?, ?, ?)',
            datetime.datetime.now(), full_message, process
        )
        mssql_cursor_global.connection.commit()
    except Exception as log_db_error:
        print(f'Fehler beim Schreiben der Tabellen-Zusammenfassung in logs: {log_db_error}')


def get_pk_columns(cursor, table_name):
    pk_query = """
        SELECT KU.COLUMN_NAME
        FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
        INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KU
          ON TC.CONSTRAINT_NAME = KU.CONSTRAINT_NAME
        WHERE TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
          AND KU.TABLE_NAME = ?
        ORDER BY KU.ORDINAL_POSITION;
    """
    cursor.execute(pk_query, (table_name,))
    return [row[0] for row in cursor.fetchall()]


def escape(val):
    if val is None:
        return 'NULL'
    val = str(val).replace("'", "''")
    return f"'{val}'"


def row_summary(columns, row):
    summary_parts = []
    for i, col in enumerate(columns):
        val = row[i]
        if isinstance(val, (int, float, str)) and len(summary_parts) < 3:
            summary_parts.append(f'{col}={repr(val)}')
    return ', '.join(summary_parts)


def main():
    global mssql_cursor_global

    try:
        mssql_connection_str = os.getenv('MSSQL_CONNECTION_STR')
        if not mssql_connection_str:
            raise ValueError('MSSQL_CONNECTION_STR nicht in der .env gefunden.')

        SDF_LOCAL_PFAD = os.getenv('SDF_LOCAL_PFAD')
        if not SDF_LOCAL_PFAD:
            raise ValueError('SDF_LOCAL_PFAD nicht in der .env gefunden.')

        sdf_file = os.path.join(SDF_LOCAL_PFAD, 'App.sdf')
        sdf_connection_str = f'Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5;Data Source={sdf_file};Persist Security Info=False;'

        tables = [
            'Addressee', 'ADR', 'AxlesArchive', 'CardEncoding', 'Carrier',
            'Coeff', 'Conveyer', 'CustomerLDB', 'Fields', 'GeneralData',
            'PDR', 'Plate', 'Product', 'RDR', 'RDR_LDB_Weighing',
            'Reason', 'Supplier', 'Tare', 'TxWeighing', 'Weighing_LDB'
        ]

        mssql_conn = pyodbc.connect(mssql_connection_str)
        mssql_cursor = mssql_conn.cursor()
        mssql_cursor_global = mssql_cursor

        sdf_conn = adodbapi.connect(sdf_connection_str)
        sdf_cursor = sdf_conn.cursor()

        report_lines = []

        for table in tables:
            try:
                write_log(f'\nVerarbeite Tabelle: {table}')
                mssql_cursor.execute(f'SELECT * FROM [{table}]')
                columns = [col[0] for col in mssql_cursor.description]
                rows = mssql_cursor.fetchall()

                write_log(f'In MSSQL gefunden: {len(rows)} Datensätze; Spalten: {columns}')

                pk_columns = get_pk_columns(mssql_cursor, table)
                if pk_columns:
                    write_log(f'Primary Key Spalte(n) für {table}: {pk_columns}')
                    pk_indices = [columns.index(pk) for pk in pk_columns]
                else:
                    write_log(f'Kein Primary Key für {table}. Es wird jeder Datensatz eingefügt.')
                    pk_indices = []

                inserted = 0
                skipped = 0
                errors = 0
                inserted_rows = []

                for row in rows:
                    try:
                        record_exists = False
                        if pk_indices:
                            pk_clause = ' AND '.join(
                                f'[{col}] = {escape(row[columns.index(col)])}' for col in pk_columns
                            )
                            select_pk_sql = f'SELECT COUNT(*) FROM [{table}] WHERE {pk_clause}'
                            sdf_cursor.execute(select_pk_sql)
                            count = sdf_cursor.fetchone()[0]
                            record_exists = count > 0

                        if record_exists:
                            skipped += 1
                            continue

                        escaped_values = ', '.join(escape(v) for v in row)
                        insert_sql = f"INSERT INTO [{table}] ({', '.join('[' + c + ']' for c in columns)}) VALUES ({escaped_values})"
                        sdf_cursor.execute(insert_sql)
                        inserted += 1
                        inserted_rows.append(row_summary(columns, row))

                    except Exception as ie:
                        errors += 1
                        error_details = f'Fehler bei Tabelle {table}: {ie}\nRow: {row}'
                        write_log(error_details)
                        mail.send_error_email(error_details, process)

                sdf_conn.commit()
                write_log_summary(table, inserted, skipped, errors, inserted_rows)
                report_lines.append(f'Tabelle {table}: {inserted} eingefügt, {skipped} übersprungen, {errors} Fehler.')

            except Exception as te:
                error_details = f'Fehler in Tabelle {table}: {te}\n{traceback.format_exc()}'
                write_log(error_details)
                mail.send_error_email(error_details, process)

        # Abschlussbericht
        report_text = '\n'.join(report_lines)
        write_log('Import-Zusammenfassung:\n' + report_text)
        mail.send_report_email(report_text, process)

        import_marker_path = os.path.join(MAIN_DIR, '.import')
        with open(import_marker_path, 'w') as f:
            f.write('')
        write_log(f'Leere .import-Datei erstellt: {import_marker_path}')

    except Exception as e:
        error_details = f'Allgemeiner Fehler beim Import: {e}\n{traceback.format_exc()}'
        write_log(error_details)
        mail.send_error_email(error_details, process)


if __name__ == '__main__':
    main()
