from datetime import datetime
import pandas as pd
import os
import json
from django.conf import settings
from users.models import AuditCategory,User
import csv

def add_system_audit_trail(category,action,message,reason,old_details,new_details,audit_added_by,branch=None):
    if not isinstance(audit_added_by, User):
        audit_added_by = User.objects.get(pk=audit_added_by)  
    requested_category = category
    category = AuditCategory.objects.filter(action_key=action).first() 
    if not category:
        category = AuditCategory.objects.filter(action_key=requested_category).first() 
 
    old_details = remove_from_dict([],old_details)
    new_details = remove_from_dict([],new_details)

    branch_id = branch.id if branch else None
    branch_name = branch.name if branch else ''
    organisation_id = branch.branch_organisation.id if branch else None
    category_id = category.id if category else 0
    category_name = category.title if category else str(action or requested_category or 'system').replace('_', ' ').title()
    
    audit_trail_field = {
        "action":action,
        "reason":reason,
        "message":message,
        'old_details':json.dumps(old_details),
        'new_details':json.dumps(new_details),
        "staff_name":audit_added_by.user_staff.name,
        "audit_added_by_id":audit_added_by.id,
        "branch_id":branch_id,
        "branch_name":branch_name,
        "audit_date_added":datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "category_id":category_id,
        "category_name":category_name,
    }
    if organisation_id:
        generate_audit_trail(organisation_id,audit_trail_field)

def remove_from_dict(keys,dictionary):
    if dictionary:
        for key in keys:
            if key in dictionary:
                del dictionary[key]
    
    if dictionary:
        for key in list(dictionary.keys()):
            if isinstance(dictionary[key], dict) or isinstance(dictionary[key], list):
                del dictionary[key]
    return dictionary

def generate_audit_trail(organisation_id,new_log):
    csv_file_name = f'{settings.STATIC_ROOT}/reports/{organisation_id}/system-audit/audit-log.csv'
    if os.path.exists(csv_file_name):
        with open(csv_file_name, 'a') as csv_file:
            writer = csv.writer(csv_file)
            writer.writerow(new_log.values())
            csv_file.close()
    else:
        organisation_directory = settings.STATIC_ROOT + f'/reports/{organisation_id}/system-audit'
        os.makedirs(organisation_directory, exist_ok=True)
        # Write to CSV file
        csv_file_name = f'{organisation_directory}/audit-log.csv'
        with open(csv_file_name, mode='w', newline='') as csv_file:
            writer = csv.writer(csv_file)
            # Writing the header
            writer.writerow(new_log.keys())
            # Writing the data rows
            writer.writerow(new_log.values())
            csv_file.close()
            
def retrieve_audit_trails(query_filters):
        audit_logs      = []
        count           = 0
        start_date      = query_filters['start_date'].strftime('%Y-%m-%d %H:%M')
        end_date        = query_filters['end_date'].strftime('%Y-%m-%d %H:%M')
        user_id         = query_filters['user_id']
        branch_id       = query_filters['branch_id']
        category_id     = query_filters['category']
        page            = query_filters['page']
        page_size       = query_filters['page_size']
        search          = query_filters['search']
        organisation_id = query_filters['organisation_id']

        start_index = (int(page) - 1) * int(page_size)
        end_index = int(page) * int(page_size)

        csv_file_name  = f'{settings.STATIC_ROOT}/reports/{organisation_id}/system-audit/audit-log.csv'
        if os.path.exists(csv_file_name):
            audit_logs = pd.read_csv(csv_file_name)
            audit_logs = audit_logs.fillna('')
            # Filter between dates
            audit_logs['audit_date_added'] = pd.to_datetime(audit_logs['audit_date_added'])
            filter_conditions = (audit_logs['audit_date_added'] >= start_date) & (audit_logs['audit_date_added'] <= end_date)
            # Filter by branch Id
            if branch_id:
                filter_conditions = filter_conditions & (audit_logs['branch_id'] == int(branch_id))
            #filter by  transaction type
            if category_id:
                filter_conditions = filter_conditions & (audit_logs['category_id'] == int(category_id))
            # Filter by user id
            if user_id:
                filter_conditions = filter_conditions & (audit_logs['audit_added_by_id'] == int(user_id))
            
            # Search Filter
            if search:
                filter_conditions = (audit_logs['reason'].str.contains(search, case=False) | audit_logs['message'].str.contains(search, case=False))
            audit_logs = audit_logs[filter_conditions]
            audit_logs = audit_logs.sort_values(by='audit_date_added', ascending=False)
            count      = len(audit_logs)
            audit_logs = audit_logs.iloc[start_index:end_index]
            results    = audit_logs.to_dict(orient='records')
            audit_logs = pd.DataFrame()
            return {"count":count,"results":results}
        return {"count":count,"results":[]}

def dict_to_custom_array(details):
    data_list = []
    if details:
        keys = list(details.keys())
        if keys:
            for key in keys:
                data_list.append({"key":key,"value":details[key]})
    return data_list
    
def update_audit_details(details,action):
    keys = []
    # Customer 
    if action in ['update_customer','delete_customer']:
        keys = [
            'id',
            'customer_branch',
            'customer_branch_id',
            'assigned_group',
            'customer_type_id',
            'branch_customer_type',
            'customer_organisation_id',
            'customer','customer_added_by',
            'has_members'
        ]

    # Customer Location
    if action in ['update_customer_location']:
        keys = [
            'id',
            'customer',
            'address_added_by',
            'customer_village_id',
            'customer_parish_id',
            'customer_subcounty_id',
            'customer_county_id',
            'customer_district_id',
            'village',
            'parish',
            'subcounty',
            'county',
            'district',
        ]

    # staff & User 
    if action in ['update_staff','delete_staff']:
        keys = ['id','staff_organisation']
    
    if action in ['user_update','user_role_update']:
        keys = [
            'id',
            'password',
            'is_staff',
            'is_superuser',
            'user_permissions',
            'user',
            'user_added_by',
            'user_organisation_branch_id',
            'groups',
            'user_staff',
            'last_login',
            'updated_password',
            'first_name',
            'last_name',
            'assigned_role'
        ]
        
    # Savings 
    if action in [
        'update_savings_product',
        'update_savings_product_charge',
        'update_savings_product_custom_charge',
        'update_savings_product_interest']:
        keys = [
            'id',
            'accounts_chart',
            'closing_fee_account',
            'saving_product_org',
            'last_updated',
            'last_updated_by''deleted',
            'saving_product_added_by',
            'is_active',
            'currency',
            'saving_product'
            ,'charge_last_updated_by',
            'interest_added_by',
            'tax_chart',
            'interest_last_updated_by',
            'charge_key'
        ]
    
    if action in [
        'update_savings_account',
        'delete_savings_account',
        'update_savings_account_blocking',
        'update_savings_account_booking']:
        keys = [
            'id',
            'customer_branch',
            'customer_branch_id',
            'opened_by','block_type'
            'account_customer',
            'account_product',
            'customer_type',
            'reference_transaction',
            'last_updated',
            'saving_account_last_updated_by',
            'customer_account',
            'chart',
            'account',
            'account_product',
            'customer_has_members',
            'blocked_amount_last_updated_by',
            'deleted'
        ]
    # Shares 
    if action in ['delete_customer_dividend_sharing','delete_staff']:
        keys = [
            'id',
            'share_dividend_added_by',
            'share_dividend_added_by'
        ]

    #loans 
    if action in ['update_loan_product']:
        keys = [
            'id',
            'chart',
            'organisation',
            'is_deleted',
            'interest_accrued_account',
            'penalty_accrued_account',
            'interest_receivable_account',
            'penalty_receivable_account',
            'expenses_from_interest_account',
            'expenses_from_penality_account',
            'interest_income_chart',
            'penalty_income_chart',
            'interest_installment_waive_off',
            'write_off_chart'
        ]
    if action in ['update_loan_application','loan_case_load_transfer']:
        keys = [
            'id',
            'loan_officer',
            'organisation_branch',
            'is_deleted',
            'reason_for_delete',
            'auto_payments_saving_account',
            'loan_group',
            'loan_sector',
            'customer',
            'loan_application_product',
            'cancel_clear_off_reason'
        ]

    if action in [
        'update_loan_security',
        'delete_loan_security',
        'update_loan_income_source',
        'delete_loan_income_source',
        'update_loan_approval',
        'delete_guarantor',
        'update_loan_non_member_guarantor']:
        keys = [
            'id',
            'loan_application',
            'guarantor_customer',
            'customer',
            'organisation_branch',
            'organ_non_member_guarantor_added_by',
            'organisation_client_non_member'
        ]
    
    if action in [
        'delete_transaction',
        'update_saving_transaction_charge',
        'update_saving_transaction',
        'update_transaction',
        'delete_saving_transaction',
        'delete_saving_transaction_charge',
        'reverse_saving_transaction',
        'reverse_saving_transaction_charge'
        'reverse_transaction',
        'reverse_share_transaction',
        'update_loan_payment',
        'delete_loan_payment',
        'reverse_loan_payment']:
        keys = [
            'id',
            'credit_chart',
            'debit_chart',
            'branch',
            'added_by',
            'deleted'
        ]

    if action in ['loan_disbursement']:
        keys = [
            'id',
            'loan_application',
            'system_transaction',
            'disbursement_account_id'
        ]

    if keys:
        for key in keys:
            if key in details:
                del details[key]

    return details
