#!/usr/bin/env python3
"""
Data access layer for NEFT inward file processing.
Handles CRUD operations and transaction management.
"""

from typing import List, Optional
from logging_config import get_logger
from .oracle_connector import get_connector
from .models import NEFTOutwardRecord, ProcessedFile

logger = get_logger(__name__)


class Repository:
    """Data access layer for NEFT inward processing."""

    def __init__(self):
        """Initialize repository with connector."""
        self.connector = get_connector()

    # ---------------------------------------------------------
    # ADDED: Account validation using last 12 digits of RECVR_ACCT_NO
    # ---------------------------------------------------------
    def validate_account_exists(self, account_number: str) -> bool:
        """
        Validate if account number exists in dep_account table.

        Args:
            account_number: Beneficiary account number (RECVR_ACCT_NO)

        Returns:
            True if account exists in dep_account.link_accno, False otherwise
        """
        if not account_number:
            return False

        last12 = str(account_number)[-12:]

        conn = self.connector.get_connection()
        try:
            cursor = conn.cursor()
            cursor.execute(
                "SELECT COUNT(*) FROM dep_account WHERE link_accno = :accno",
                {'accno': last12}
            )
            count = cursor.fetchone()[0]
            return count > 0
        except Exception as e:
            logger.warning(f"Error validating account {account_number}: {e}")
            return False
        finally:
            cursor.close()
            conn.close()

    # ---------------------------------------------------------
    # UPDATED: bulk_insert_transactions WITH VALIDATION        
    # ---------------------------------------------------------
    def bulk_insert_transactions(self, transactions: List[NEFTOutwardRecord]) -> tuple:
        """
        Bulk insert NEFT transactions into outward_neft_api_log.
        Records with invalid beneficiary account numbers are skipped.

        Args:
            transactions: List of NEFTOutwardRecord objects

        Returns:
            (inserted_count, skipped_count)
        """
        if not transactions:
            logger.warning("No transactions to insert")
            return 0, 0

        valid_transactions = []
        skipped_count = 0

        
        for txn in transactions:
            acct = txn.sender_acct_no

            if self.validate_account_exists(acct):
                valid_transactions.append(txn)
            else:
                skipped_count += 1

        if not valid_transactions:
            logger.debug(f"All {skipped_count} transactions skipped (invalid Remitter accounts)")
            return 0, skipped_count

        conn = self.connector.get_connection()
        cursor = None
        try:
            cursor = conn.cursor()

            batch_data = [txn.to_dict() for txn in valid_transactions]
            logger.info(batch_data)

            insert_sql = """
                INSERT INTO outward_neft_api_log (
                    TXNIND,
                    JRNL_ID,
                    BANKCODE,
                    REF_NO,
                    TRAN_DATE,
                    TXN_AMT,
                    SENDER_IFSC,
                    RECIEVER_IFSC,
                    SENDER_ACCT_NO,
                    SENDER_NAME,                   
                    RECVR_ACCT_NO,
                    RECIEVER_NAME,                    
                    REJECT_CODE,
                    REJECT_REASON,
                    BENEFICIARY_ADDRESS,
                    MSG_TYPE,
                    SENDER_TO_RECIVER_INFO
                ) VALUES (
                    :TXNIND,
                    :JRNL_ID,
                    :BANKCODE,
                    :REF_NO,
                    :TRAN_DATE,
                    :TXN_AMT,
                    :SENDER_IFSC,
                    :RECIEVER_IFSC,
                    :SENDER_ACCT_NO,
                    :SENDER_NAME,                    
                    :RECVR_ACCT_NO,
                    :RECIEVER_NAME,                    
                    :REJECT_CODE,
                    :REJECT_REASON,
                    :BENEFICIARY_ADDRESS,
                    :MSG_TYPE,
                    :SENDER_TO_RECIVER_INFO 
                )
            """

            cursor.executemany(insert_sql, batch_data)
            conn.commit()

            inserted_count = len(valid_transactions)
            logger.info(f"Inserted {inserted_count} NEFT transactions into outward_neft_api_log")
            return inserted_count, skipped_count

        except Exception as e:
            if conn:
                conn.rollback()
            logger.error(f"Error inserting NEFT transactions: {e}", exc_info=True)
            raise
        finally:
            if cursor:
                cursor.close()
            conn.close()

    # ---------------------------------------------------------
    # NOTHING ELSE BELOW THIS LINE WAS TOUCHED
    # ---------------------------------------------------------

    def is_file_processed(self, filename: str, bankcode: str) -> bool:
        conn = self.connector.get_connection()
        cursor = None
        try:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT COUNT(*)
                  FROM neft_processed_files
                 WHERE filename = :filename
                   AND bankcode = :bankcode
                """,
                {'filename': filename, 'bankcode': bankcode}
            )
            count = cursor.fetchone()[0]
            return count > 0
        except Exception as e:
            logger.error(f"Error checking processed file: {e}", exc_info=True)
            return False
        finally:
            if cursor:
                cursor.close()
            conn.close()

    def mark_file_processed(self, processed_file: ProcessedFile) -> bool:
        conn = self.connector.get_connection()
        cursor = None
        try:
            cursor = conn.cursor()

            file_data = processed_file.to_dict()
            insert_sql = """
                INSERT INTO neft_processed_files (
                    filename, bankcode, file_path, transaction_count,
                    status, error_message, processed_at
                ) VALUES (
                    :filename, :bankcode, :file_path, :transaction_count,
                    :status, :error_message, :processed_at
                )
            """

            cursor.execute(insert_sql, file_data)
            conn.commit()

            logger.info(f"Marked file as processed: {processed_file.filename}")
            return True

        except Exception as e:
            if conn:
                conn.rollback()
            logger.error(f"Error marking file as processed: {e}", exc_info=True)
            return False
        finally:
            if cursor:
                cursor.close()
            conn.close()

    def get_processed_files(self, bankcode: Optional[str] = None) -> List[str]:
        conn = self.connector.get_connection()
        cursor = None
        try:
            cursor = conn.cursor()

            if bankcode:
                cursor.execute(
                    """
                    SELECT filename
                      FROM neft_processed_files
                     WHERE bankcode = :bankcode
                     ORDER BY processed_at DESC
                    """,
                    {'bankcode': bankcode}
                )
            else:
                cursor.execute(
                    """
                    SELECT filename
                      FROM neft_processed_files
                     ORDER BY processed_at DESC
                    """
                )

            filenames = [row[0] for row in cursor.fetchall()]
            return filenames

        except Exception as e:
            logger.error(f"Error retrieving processed files: {e}", exc_info=True)
            return []
        finally:
            if cursor:
                cursor.close()
            conn.close()

    def call_neft_api_txn_post(self) -> bool:
        conn = self.connector.get_connection()
        cursor = None
        try:
            cursor = conn.cursor()
            logger.info("Calling neft_api_txn_post procedure to process all inserted transactions...")

            try:
                cursor.callproc('neft_api_txn_post')
            except Exception:
                cursor.execute("BEGIN neft_api_txn_post; END;")

            conn.commit()
            logger.info("neft_api_txn_post procedure executed successfully")
            return True
        except Exception as e:
            logger.error(f"Error calling neft_api_txn_post procedure: {e}", exc_info=True)
            return False
        finally:
            if cursor:
                cursor.close()
            conn.close()

    def verify_tables_exist(self):
        conn = self.connector.get_connection()
        cursor = None
        try:
            cursor = conn.cursor()

            try:
                cursor.execute("SELECT COUNT(*) FROM outward_neft_api_log WHERE ROWNUM = 1")
                logger.info("✓ inoutward_neft_api_log table exists")
            except Exception as e:
                logger.error(f"✗ inoutward_neft_api_log table not found: {e}")
                raise SystemExit(
                    "FATAL: outward_neft_api_log table must be created manually before running this application"
                )

            try:
                cursor.execute("SELECT COUNT(*) FROM neft_processed_files WHERE ROWNUM = 1")
                logger.info("✓ neft_processed_files table exists")
            except Exception as e:
                logger.error(f"✗ neft_processed_files table not found: {e}")
                raise SystemExit(
                    "FATAL: neft_processed_files table must be created manually before running this application"
                )

            logger.info("Database tables verified successfully")

        except SystemExit:
            raise
        except Exception as e:
            logger.error(f"Error verifying tables: {e}", exc_info=True)
            raise SystemExit(f"FATAL: Error verifying database tables: {e}")
        finally:
            if cursor:
                cursor.close()
            conn.close()
