"""
معالج ملفات Excel
"""

import pandas as pd
import os
import numpy as np
import xlsxwriter
from datetime import datetime
import traceback
import config
from utils.helpers import create_directory_if_not_exists, get_file_extension, format_number


def read_excel_file(file_path, sheet_name=0, header=0, skip_rows=None):
    """
    قراءة ملف Excel
    
    المعلمات:
        file_path: مسار ملف Excel
        sheet_name: اسم أو رقم الصفحة (افتراضي: 0)
        header: رقم الصف الذي يحتوي على العناوين (افتراضي: 0)
        skip_rows: قائمة بأرقام الصفوف للتخطي (افتراضي: None)
        
    الإرجاع:
        DataFrame من البيانات المقروءة
    """
    try:
        # التحقق من وجود الملف
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"الملف غير موجود: {file_path}")
        
        # التحقق من امتداد الملف
        ext = get_file_extension(file_path)
        if ext not in ['.xlsx', '.xls', '.xlsm']:
            raise ValueError(f"نوع الملف غير مدعوم: {ext}. يجب أن يكون الملف بامتداد .xlsx أو .xls أو .xlsm")
        
        # قراءة الملف
        df = pd.read_excel(
            file_path,
            sheet_name=sheet_name,
            header=header,
            skiprows=skip_rows
        )
        
        return df
    
    except Exception as e:
        error_msg = f"خطأ في قراءة ملف Excel: {str(e)}"
        print(error_msg)
        traceback.print_exc()
        raise Exception(error_msg)


def write_excel_file(df, file_path, sheet_name="Sheet1", index=False, freeze_panes=None, column_widths=None, formats=None):
    """
    كتابة DataFrame إلى ملف Excel
    
    المعلمات:
        df: DataFrame المراد كتابته
        file_path: مسار ملف Excel
        sheet_name: اسم الصفحة (افتراضي: Sheet1)
        index: ما إذا كان سيتم تضمين الفهرس (افتراضي: False)
        freeze_panes: صف وعمود لتجميد الألواح (افتراضي: None)
        column_widths: قاموس لعرض الأعمدة {column_name: width}
        formats: قاموس لتنسيقات الأعمدة {column_name: format_function}
        
    الإرجاع:
        True في حالة النجاح
    """
    try:
        # التأكد من وجود المجلد
        create_directory_if_not_exists(os.path.dirname(file_path))
        
        # تحديد المكتب والورقة
        writer = pd.ExcelWriter(file_path, engine='xlsxwriter')
        df.to_excel(writer, sheet_name=sheet_name, index=index)
        
        # الحصول على مرجع لورقة العمل
        workbook = writer.book
        worksheet = writer.sheets[sheet_name]
        
        # إنشاء تنسيقات مخصصة
        header_format = workbook.add_format({
            'bold': True,
            'bg_color': '#CCCCCC',
            'border': 1,
            'align': 'center',
            'valign': 'vcenter',
            'text_wrap': True
        })
        
        number_format = workbook.add_format({
            'num_format': '#,##0.00',
            'align': 'right'
        })
        
        currency_format = workbook.add_format({
            'num_format': '_-* #,##0.00 [$ريال]_-;-* #,##0.00 [$ريال]_-;_-* "-" [$ريال]_-;_-@_-',
            'align': 'right'
        })
        
        date_format = workbook.add_format({
            'num_format': 'yyyy-mm-dd',
            'align': 'center'
        })
        
        text_format = workbook.add_format({
            'align': 'right',
            'text_wrap': True
        })
        
        # تطبيق التنسيقات على العناوين
        for col_num, value in enumerate(df.columns.values):
            worksheet.write(0, col_num + (1 if index else 0), value, header_format)
        
        # تعيين حجم الأعمدة
        if column_widths:
            for col_name, width in column_widths.items():
                if col_name in df.columns:
                    col_idx = df.columns.get_loc(col_name) + (1 if index else 0)
                    worksheet.set_column(col_idx, col_idx, width)
        else:
            # ضبط عرض الأعمدة تلقائيًا
            for col_num, col_name in enumerate(df.columns):
                max_len = df[col_name].astype(str).map(len).max()
                col_len = max(max_len, len(str(col_name))) + 2
                worksheet.set_column(col_num + (1 if index else 0), col_num + (1 if index else 0), col_len)
        
        # تطبيق التنسيقات حسب نوع البيانات
        for row_num in range(len(df)):
            for col_num, col_name in enumerate(df.columns):
                cell_value = df.iloc[row_num, col_num]
                cell_format = text_format
                
                # تحديد التنسيق المناسب بناءً على نوع البيانات
                if pd.api.types.is_numeric_dtype(df[col_name].dtype):
                    if any(curr in col_name.lower() for curr in ['سعر', 'تكلفة', 'قيمة', 'مبلغ', 'ريال']):
                        cell_format = currency_format
                    else:
                        cell_format = number_format
                elif pd.api.types.is_datetime64_dtype(df[col_name].dtype):
                    cell_format = date_format
                
                # استخدام تنسيق مخصص إذا تم توفيره
                if formats and col_name in formats:
                    custom_format = formats[col_name]
                    if callable(custom_format):
                        # إذا كان دالة، استدعاها لتطبيق التنسيق
                        cell_value = custom_format(cell_value)
                    else:
                        # إذا كان تنسيق، استخدمه
                        cell_format = custom_format
                
                worksheet.write(row_num + 1, col_num + (1 if index else 0), cell_value, cell_format)
        
        # تجميد الألواح إذا تم تحديده
        if freeze_panes:
            worksheet.freeze_panes(*freeze_panes)
        
        # حفظ الملف
        writer.close()
        
        return True
    
    except Exception as e:
        error_msg = f"خطأ في كتابة ملف Excel: {str(e)}"
        print(error_msg)
        traceback.print_exc()
        raise Exception(error_msg)


def export_to_excel(data, file_path, sheet_name="Sheet1", customize_func=None):
    """
    تصدير البيانات إلى ملف Excel مع خيارات تخصيص
    
    المعلمات:
        data: DataFrame أو قاموس من DataFrames للتصدير
        file_path: مسار ملف Excel
        sheet_name: اسم الصفحة (افتراضي: Sheet1)
        customize_func: دالة لتخصيص المصنف قبل الحفظ (افتراضي: None)
        
    الإرجاع:
        True في حالة النجاح
    """
    try:
        # التأكد من وجود المجلد
        create_directory_if_not_exists(os.path.dirname(file_path))
        
        # إنشاء كائن الكاتب
        writer = pd.ExcelWriter(file_path, engine='xlsxwriter')
        
        # تصدير البيانات
        if isinstance(data, pd.DataFrame):
            # إذا كان DataFrame واحد
            data.to_excel(writer, sheet_name=sheet_name, index=False)
        elif isinstance(data, dict):
            # إذا كان قاموس من DataFrames
            for sheet, df in data.items():
                if isinstance(df, pd.DataFrame):
                    df.to_excel(writer, sheet_name=sheet, index=False)
        else:
            raise ValueError("البيانات يجب أن تكون DataFrame أو قاموس من DataFrames")
        
        # تطبيق التخصيص إذا تم توفيره
        if customize_func and callable(customize_func):
            customize_func(writer)
        
        # حفظ الملف
        writer.close()
        
        return True
    
    except Exception as e:
        error_msg = f"خطأ في تصدير البيانات إلى Excel: {str(e)}"
        print(error_msg)
        traceback.print_exc()
        raise Exception(error_msg)


def read_sheets_from_excel(file_path):
    """
    قراءة جميع صفحات ملف Excel
    
    المعلمات:
        file_path: مسار ملف Excel
        
    الإرجاع:
        قاموس من DataFrames بأسماء الصفحات كمفاتيح
    """
    try:
        # التحقق من وجود الملف
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"الملف غير موجود: {file_path}")
        
        # التحقق من امتداد الملف
        ext = get_file_extension(file_path)
        if ext not in ['.xlsx', '.xls', '.xlsm']:
            raise ValueError(f"نوع الملف غير مدعوم: {ext}. يجب أن يكون الملف بامتداد .xlsx أو .xls أو .xlsm")
        
        # قراءة جميع الصفحات من الملف
        excel_file = pd.ExcelFile(file_path)
        sheets = {}
        
        for sheet_name in excel_file.sheet_names:
            sheets[sheet_name] = pd.read_excel(excel_file, sheet_name=sheet_name)
        
        return sheets
    
    except Exception as e:
        error_msg = f"خطأ في قراءة صفحات ملف Excel: {str(e)}"
        print(error_msg)
        traceback.print_exc()
        raise Exception(error_msg)


def create_excel_report(data_dict, file_path, formats=None, column_widths=None, title=None, subtitle=None):
    """
    إنشاء تقرير Excel متقدم
    
    المعلمات:
        data_dict: قاموس من DataFrames للتصدير {sheet_name: DataFrame}
        file_path: مسار ملف Excel
        formats: قاموس للتنسيقات {sheet_name: {column_name: format}}
        column_widths: قاموس لعرض الأعمدة {sheet_name: {column_name: width}}
        title: عنوان التقرير
        subtitle: العنوان الفرعي للتقرير
        
    الإرجاع:
        True في حالة النجاح
    """
    try:
        # التأكد من وجود المجلد
        create_directory_if_not_exists(os.path.dirname(file_path))
        
        # إنشاء كائن الكاتب
        writer = pd.ExcelWriter(file_path, engine='xlsxwriter')
        workbook = writer.book
        
        # إنشاء التنسيقات العامة
        header_format = workbook.add_format({
            'bold': True,
            'bg_color': '#CCCCCC',
            'border': 1,
            'align': 'center',
            'valign': 'vcenter',
            'text_wrap': True
        })
        
        title_format = workbook.add_format({
            'bold': True,
            'font_size': 16,
            'align': 'center',
            'valign': 'vcenter',
            'bg_color': '#E0E0E0',
            'border': 2
        })
        
        subtitle_format = workbook.add_format({
            'font_size': 12,
            'align': 'center',
            'valign': 'vcenter',
            'bg_color': '#E0E0E0',
            'border': 1
        })
        
        date_format = workbook.add_format({
            'num_format': 'yyyy-mm-dd',
            'align': 'center'
        })
        
        number_format = workbook.add_format({
            'num_format': '#,##0.00',
            'align': 'right'
        })
        
        currency_format = workbook.add_format({
            'num_format': '_-* #,##0.00 [$ريال]_-;-* #,##0.00 [$ريال]_-;_-* "-" [$ريال]_-;_-@_-',
            'align': 'right'
        })
        
        percent_format = workbook.add_format({
            'num_format': '0.00%',
            'align': 'right'
        })
        
        text_format = workbook.add_format({
            'align': 'right',
            'text_wrap': True
        })
        
        # تصدير البيانات
        current_row = 0
        
        # إضافة العنوان والعنوان الفرعي إذا تم توفيرهما
        if title or subtitle:
            for sheet_name in data_dict.keys():
                worksheet = workbook.add_worksheet(sheet_name)
                current_row = 0
                
                if title:
                    worksheet.merge_range('A1:J1', title, title_format)
                    current_row += 1
                
                if subtitle:
                    worksheet.merge_range(f'A{current_row + 1}:J{current_row + 1}', subtitle, subtitle_format)
                    current_row += 1
                
                # إضافة فاصل
                current_row += 1
                
                # كتابة البيانات
                df = data_dict[sheet_name]
                df.to_excel(writer, sheet_name=sheet_name, startrow=current_row, index=False)
                
                # تنسيق العناوين
                for col_num, value in enumerate(df.columns.values):
                    worksheet.write(current_row, col_num, value, header_format)
                
                # تطبيق التنسيقات المخصصة
                if formats and sheet_name in formats:
                    sheet_formats = formats[sheet_name]
                    for col_name, fmt in sheet_formats.items():
                        if col_name in df.columns:
                            col_idx = df.columns.get_loc(col_name)
                            for row_num in range(len(df)):
                                cell_value = df.iloc[row_num, col_idx]
                                worksheet.write(row_num + current_row + 1, col_idx, cell_value, fmt)
                
                # تعيين عرض الأعمدة
                if column_widths and sheet_name in column_widths:
                    sheet_widths = column_widths[sheet_name]
                    for col_name, width in sheet_widths.items():
                        if col_name in df.columns:
                            col_idx = df.columns.get_loc(col_name)
                            worksheet.set_column(col_idx, col_idx, width)
                else:
                    # ضبط عرض الأعمدة تلقائيًا
                    for col_num, col_name in enumerate(df.columns):
                        max_len = df[col_name].astype(str).map(len).max()
                        col_len = max(max_len, len(str(col_name))) + 2
                        worksheet.set_column(col_num, col_num, col_len)
        else:
            # إذا لم يتم توفير عنوان أو عنوان فرعي، استخدم الطريقة العادية
            for sheet_name, df in data_dict.items():
                df.to_excel(writer, sheet_name=sheet_name, index=False)
                worksheet = writer.sheets[sheet_name]
                
                # تنسيق العناوين
                for col_num, value in enumerate(df.columns.values):
                    worksheet.write(0, col_num, value, header_format)
                
                # تطبيق التنسيقات المخصصة
                if formats and sheet_name in formats:
                    sheet_formats = formats[sheet_name]
                    for col_name, fmt in sheet_formats.items():
                        if col_name in df.columns:
                            col_idx = df.columns.get_loc(col_name)
                            for row_num in range(len(df)):
                                cell_value = df.iloc[row_num, col_idx]
                                worksheet.write(row_num + 1, col_idx, cell_value, fmt)
                
                # تعيين عرض الأعمدة
                if column_widths and sheet_name in column_widths:
                    sheet_widths = column_widths[sheet_name]
                    for col_name, width in sheet_widths.items():
                        if col_name in df.columns:
                            col_idx = df.columns.get_loc(col_name)
                            worksheet.set_column(col_idx, col_idx, width)
                else:
                    # ضبط عرض الأعمدة تلقائيًا
                    for col_num, col_name in enumerate(df.columns):
                        max_len = df[col_name].astype(str).map(len).max()
                        col_len = max(max_len, len(str(col_name))) + 2
                        worksheet.set_column(col_num, col_num, col_len)
        
        # حفظ الملف
        writer.close()
        
        return True
    
    except Exception as e:
        error_msg = f"خطأ في إنشاء تقرير Excel: {str(e)}"
        print(error_msg)
        traceback.print_exc()
        raise Exception(error_msg)


def extract_data_from_excel(file_path, columns_mapping=None, sheet_name=0, header_row=0, data_start_row=1):
    """
    استخراج بيانات منظمة من ملف Excel
    
    المعلمات:
        file_path: مسار ملف Excel
        columns_mapping: قاموس لتخطيط الأعمدة {اسم_العمود_الجديد: اسم_العمود_الأصلي}
        sheet_name: اسم أو رقم الصفحة (افتراضي: 0)
        header_row: رقم صف العناوين (افتراضي: 0)
        data_start_row: رقم صف بداية البيانات (افتراضي: 1)
        
    الإرجاع:
        DataFrame من البيانات المستخرجة
    """
    try:
        # قراءة الملف
        df = pd.read_excel(
            file_path,
            sheet_name=sheet_name,
            header=header_row,
            skiprows=range(1, data_start_row) if data_start_row > 1 else None
        )
        
        # تنظيف العناوين (إزالة المسافات الزائدة)
        df.columns = df.columns.str.strip()
        
        # إعادة تسمية الأعمدة إذا تم توفير تخطيط
        if columns_mapping:
            # التحقق من وجود جميع الأعمدة المطلوبة
            missing_columns = [col for col in columns_mapping.values() if col not in df.columns]
            if missing_columns:
                raise ValueError(f"الأعمدة التالية غير موجودة في الملف: {', '.join(missing_columns)}")
            
            # إعادة تسمية الأعمدة
            df = df.rename(columns={v: k for k, v in columns_mapping.items()})
            
            # اختيار الأعمدة المطلوبة فقط
            df = df[list(columns_mapping.keys())]
        
        # تنظيف البيانات
        for col in df.columns:
            # تحويل الأعمدة النصية
            if df[col].dtype == 'object':
                df[col] = df[col].astype(str).str.strip()
                
                # محاولة تحويل الأعمدة الرقمية
                try:
                    df[col] = pd.to_numeric(df[col], errors='ignore')
                except:
                    pass
        
        return df
    
    except Exception as e:
        error_msg = f"خطأ في استخراج البيانات من ملف Excel: {str(e)}"
        print(error_msg)
        traceback.print_exc()
        raise Exception(error_msg)