<?php

namespace App\Http\Controllers;

use App\Models\JournalEntry;
use App\Models\JournalEntryItem;
use App\Models\ChartOfAccount;
use App\Models\FiscalYear;
use App\Models\AccountingPeriod;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class JournalEntryController extends Controller
{
    /**
     * التحقق من توازن القيد المحاسبي وتصحيحه تلقائيًا إذا كان الفرق صغيرًا
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|null  يعيد مصفوفة تحتوي على رسالة الخطأ وحالة التوجيه إذا كان القيد غير متوازن، أو null إذا كان متوازنًا
     */
    private function checkAndFixJournalEntryBalance(Request $request)
    {
        // حساب إجمالي المدين والدائن
        $totalDebit = 0;
        $totalCredit = 0;

        foreach ($request->items as $item) {
            $totalDebit += floatval($item['debit'] ?? 0);
            $totalCredit += floatval($item['credit'] ?? 0);
        }

        $difference = abs($totalDebit - $totalCredit);

        // إذا كان الفرق أقل من 0.01، نعتبر القيد متوازنًا
        if ($difference <= 0.01) {
            return null;
        }

        // إذا كان الفرق صغيرًا (أقل من 1)، نحاول تصحيحه تلقائيًا
        if ($difference < 1) {
            // البحث عن حساب فروق ميزان المراجعة
            $adjustmentAccount = ChartOfAccount::where('account_code', 'ADJ-DIFF')->first();

            if ($adjustmentAccount) {
                // إضافة بند تصحيح إلى القيد
                $adjustmentItem = [
                    'account_id' => $adjustmentAccount->id,
                    'description' => 'تصحيح تلقائي لفرق ميزان المراجعة'
                ];

                if ($totalDebit > $totalCredit) {
                    // إذا كان المدين أكبر، نضيف بند دائن
                    $adjustmentItem['debit'] = 0;
                    $adjustmentItem['credit'] = $difference;
                } else {
                    // إذا كان الدائن أكبر، نضيف بند مدين
                    $adjustmentItem['debit'] = $difference;
                    $adjustmentItem['credit'] = 0;
                }

                // إضافة البند إلى القيد
                $request->merge(['items' => array_merge($request->items, [$adjustmentItem])]);

                // تسجيل التصحيح في ملف السجل
                \Illuminate\Support\Facades\Log::info('تم تصحيح قيد غير متوازن تلقائيًا', [
                    'entry_number' => $request->entry_number,
                    'difference' => $difference,
                    'adjustment_account' => $adjustmentAccount->account_code
                ]);

                // إظهار رسالة للمستخدم
                session()->flash('warning', 'تم تصحيح فرق بسيط في القيد المحاسبي تلقائيًا (' . $difference . ') باستخدام حساب فروق ميزان المراجعة');

                return null;
            } else {
                return [
                    'error' => 'القيد المحاسبي غير متوازن. مجموع المدين: ' . $totalDebit . '، مجموع الدائن: ' . $totalCredit . '. لم يتم العثور على حساب فروق ميزان المراجعة لتصحيح الفرق تلقائيًا.',
                    'redirect' => 'back'
                ];
            }
        } else {
            // إذا كان الفرق كبيرًا، نطلب من المستخدم تصحيحه يدويًا
            return [
                'error' => 'القيد المحاسبي غير متوازن. مجموع المدين: ' . $totalDebit . '، مجموع الدائن: ' . $totalCredit . '. الفرق: ' . $difference,
                'redirect' => 'back'
            ];
        }
    }
    /**
     * عرض قائمة القيود المحاسبية
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $user = Auth::user();
        $query = JournalEntry::with(['fiscalYear', 'accountingPeriod', 'creator', 'items', 'cashTransactions']);

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        } else if ($request->has('company_id')) {
            $query->where('company_id', $request->company_id);
        }

        // إضافة فلتر للبحث عن القيود المرتبطة بمعاملات الخزينة
        if ($request->has('source') && $request->source == 'cash_transactions') {
            $query->whereHas('cashTransactions');
        }

        // إضافة فلتر للبحث عن القيود حسب النوع (إيداع أو سحب)
        if ($request->has('transaction_type')) {
            $query->whereHas('cashTransactions', function ($q) use ($request) {
                $q->where('type', $request->transaction_type);
            });
        }

        $entries = $query->orderBy('entry_date', 'desc')
            ->paginate(15);

        return view('accounting.journal_entries.index', compact('entries'));
    }

    /**
     * عرض نموذج إنشاء قيد محاسبي جديد
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        $user = Auth::user();
        $companyId = $user->isSystemAdmin() ? ($request->company_id ?? $user->company_id) : $user->company_id;

        // التحقق من صلاحية المستخدم
        if (!$user->can('create_journal_entries')) {
            return redirect()->route('journal-entries.index')
                ->with('error', 'ليس لديك صلاحية لإنشاء قيود محاسبية جديدة');
        }

        if ($user->isSystemAdmin() && !$companyId) {
            $companies = \App\Models\Company::all();
            return view('accounting.journal_entries.select_company', compact('companies'));
        }

        // البحث عن السنة المالية والفترة المحاسبية النشطة
        $fiscalYear = FiscalYear::where('company_id', $companyId)
            ->where('is_active', true)
            ->where('is_closed', false)
            ->first();

        if (!$fiscalYear) {
            return redirect()->route('fiscal-years.index', ['company_id' => $companyId])
                ->with('error', 'لا توجد سنة مالية نشطة لهذه الشركة. يرجى إنشاء سنة مالية أولاً.');
        }

        $accountingPeriods = AccountingPeriod::where('fiscal_year_id', $fiscalYear->id)
            ->where('is_closed', false)
            ->orderBy('start_date')
            ->get();

        if ($accountingPeriods->isEmpty()) {
            return redirect()->route('accounting-periods.index', ['company_id' => $companyId])
                ->with('error', 'لا توجد فترات محاسبية نشطة لهذه الشركة. يرجى إنشاء فترة محاسبية أولاً.');
        }

        // الحصول على الحسابات الفرعية فقط (غير الرئيسية)
        $accounts = ChartOfAccount::where('company_id', $companyId)
            ->where('is_active', true)
            ->where('is_parent', false)  // الحسابات التي تم تعيينها كفرعية فقط
            ->orderBy('account_code')
            ->get();

        $entryNumber = JournalEntry::generateEntryNumber($companyId);

        return view('accounting.journal_entries.create', compact('fiscalYear', 'accountingPeriods', 'accounts', 'entryNumber', 'companyId'));
    }

    /**
     * حفظ قيد محاسبي جديد
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        // التحقق من صلاحية المستخدم
        if (!Auth::user()->can('create_journal_entries')) {
            return redirect()->route('journal-entries.index')
                ->with('error', 'ليس لديك صلاحية لإنشاء قيود محاسبية جديدة');
        }
        $validator = Validator::make($request->all(), [
            'entry_number' => 'required|string|max:255|unique:journal_entries,entry_number',
            'entry_date' => 'required|date',
            'fiscal_year_id' => 'required|exists:fiscal_years,id',
            'accounting_period_id' => 'required|exists:accounting_periods,id',
            'description' => 'nullable|string',
            'reference_type' => 'nullable|string|max:255',
            'reference_id' => 'nullable|integer',
            'items' => 'required|array|min:2',
            'items.*.account_id' => 'required|exists:chart_of_accounts,id',
            'items.*.debit' => 'required_without:items.*.credit|numeric|min:0',
            'items.*.credit' => 'required_without:items.*.debit|numeric|min:0',
            'items.*.description' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        // التحقق من توازن القيد المحاسبي
        $totalDebit = 0;
        $totalCredit = 0;

        foreach ($request->items as $item) {
            $totalDebit += floatval($item['debit'] ?? 0);
            $totalCredit += floatval($item['credit'] ?? 0);
        }

        if (abs($totalDebit - $totalCredit) > 0.01) {
            return redirect()->back()
                ->with('error', 'القيد المحاسبي غير متوازن. مجموع المدين: ' . $totalDebit . '، مجموع الدائن: ' . $totalCredit)
                ->withInput();
        }

        // التحقق من أن الفترة المحاسبية تنتمي للسنة المالية المحددة
        $accountingPeriod = AccountingPeriod::findOrFail($request->accounting_period_id);
        if ($accountingPeriod->fiscal_year_id != $request->fiscal_year_id) {
            return redirect()->back()
                ->with('error', 'الفترة المحاسبية المحددة لا تنتمي للسنة المالية المحددة')
                ->withInput();
        }

        // التحقق من أن تاريخ القيد ضمن الفترة المحاسبية
        if (!$accountingPeriod->isDateWithinPeriod($request->entry_date)) {
            return redirect()->back()
                ->with('error', 'تاريخ القيد خارج نطاق الفترة المحاسبية المحددة')
                ->withInput();
        }

        DB::beginTransaction();

        try {
            // التحقق من السنة المالية والحصول على معرف الشركة
            $fiscalYear = FiscalYear::findOrFail($request->fiscal_year_id);
            $companyId = $fiscalYear->company_id;

            // إنشاء القيد المحاسبي
            $entry = new JournalEntry();
            $entry->company_id = $companyId;
            $entry->fiscal_year_id = $request->fiscal_year_id;
            $entry->accounting_period_id = $request->accounting_period_id;
            $entry->entry_number = $request->entry_number;
            $entry->entry_date = $request->entry_date;
            $entry->description = $request->description;
            $entry->reference_type = $request->reference_type;
            $entry->reference_id = $request->reference_id;
            $entry->is_posted = false;
            $entry->is_approved = false;
            $entry->created_by = Auth::id();
            $entry->save();

            // إنشاء بنود القيد المحاسبي
            foreach ($request->items as $itemData) {
                $item = new JournalEntryItem();
                $item->journal_entry_id = $entry->id;
                $item->account_id = $itemData['account_id'];
                $item->debit = floatval($itemData['debit'] ?? 0);
                $item->credit = floatval($itemData['credit'] ?? 0);
                $item->description = $itemData['description'] ?? null;
                $item->save();
            }

            DB::commit();

            return redirect()->route('journal-entries.show', $entry->id)
                ->with('success', 'تم إنشاء القيد المحاسبي بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء إنشاء القيد المحاسبي: ' . $e->getMessage())
                ->withInput();
        }
    }

    /**
     * عرض تفاصيل قيد محاسبي محدد
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $user = Auth::user();
        $query = JournalEntry::with(['fiscalYear', 'accountingPeriod', 'items.account', 'creator', 'approver']);

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        return view('accounting.journal_entries.show', compact('entry'));
    }

    /**
     * عرض نموذج تعديل قيد محاسبي
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $user = Auth::user();
        $query = JournalEntry::with(['fiscalYear', 'accountingPeriod', 'items.account']);

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد غير مرحل وغير معتمد
        if ($entry->is_posted || $entry->is_approved) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'لا يمكن تعديل القيد المحاسبي لأنه مرحل أو معتمد');
        }

        $fiscalYears = FiscalYear::where('company_id', $entry->company_id)
            ->where('is_closed', false)
            ->orderBy('start_date', 'desc')
            ->get();

        $accountingPeriods = AccountingPeriod::where('fiscal_year_id', $entry->fiscal_year_id)
            ->where('is_closed', false)
            ->orderBy('start_date')
            ->get();

        // الحصول على الحسابات الفرعية فقط (غير الرئيسية)
        $accounts = ChartOfAccount::where('company_id', $entry->company_id)
            ->where('is_active', true)
            ->where(function ($query) {
                $query->where('is_parent', false)  // الحسابات التي تم تعيينها صراحة كفرعية
                    ->orWhereNull('is_parent');  // للتوافق مع السجلات القديمة التي لم يتم تعيين is_parent لها
            })
            ->orderBy('account_code')
            ->get();

        return view('accounting.journal_entries.edit', compact('entry', 'fiscalYears', 'accountingPeriods', 'accounts'));
    }

    /**
     * تحديث قيد محاسبي محدد
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $user = Auth::user();
        $query = JournalEntry::query();

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد غير مرحل وغير معتمد
        if ($entry->is_posted || $entry->is_approved) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'لا يمكن تعديل القيد المحاسبي لأنه مرحل أو معتمد');
        }

        $validator = Validator::make($request->all(), [
            'entry_number' => 'required|string|max:255|unique:journal_entries,entry_number,' . $id,
            'entry_date' => 'required|date',
            'fiscal_year_id' => 'required|exists:fiscal_years,id',
            'accounting_period_id' => 'required|exists:accounting_periods,id',
            'description' => 'nullable|string',
            'reference_type' => 'nullable|string|max:255',
            'reference_id' => 'nullable|integer',
            'items' => 'required|array|min:2',
            'items.*.account_id' => 'required|exists:chart_of_accounts,id',
            'items.*.debit' => 'required_without:items.*.credit|numeric|min:0',
            'items.*.credit' => 'required_without:items.*.debit|numeric|min:0',
            'items.*.description' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        // التحقق من توازن القيد المحاسبي
        $totalDebit = 0;
        $totalCredit = 0;

        foreach ($request->items as $item) {
            $totalDebit += floatval($item['debit'] ?? 0);
            $totalCredit += floatval($item['credit'] ?? 0);
        }

        if (abs($totalDebit - $totalCredit) > 0.01) {
            return redirect()->back()
                ->with('error', 'القيد المحاسبي غير متوازن. مجموع المدين: ' . $totalDebit . '، مجموع الدائن: ' . $totalCredit)
                ->withInput();
        }

        // التحقق من أن الفترة المحاسبية تنتمي للسنة المالية المحددة
        $accountingPeriod = AccountingPeriod::findOrFail($request->accounting_period_id);
        if ($accountingPeriod->fiscal_year_id != $request->fiscal_year_id) {
            return redirect()->back()
                ->with('error', 'الفترة المحاسبية المحددة لا تنتمي للسنة المالية المحددة')
                ->withInput();
        }

        // التحقق من أن تاريخ القيد ضمن الفترة المحاسبية
        if (!$accountingPeriod->isDateWithinPeriod($request->entry_date)) {
            return redirect()->back()
                ->with('error', 'تاريخ القيد خارج نطاق الفترة المحاسبية المحددة')
                ->withInput();
        }

        DB::beginTransaction();

        try {
            // تحديث القيد المحاسبي
            $entry->fiscal_year_id = $request->fiscal_year_id;
            $entry->accounting_period_id = $request->accounting_period_id;
            $entry->entry_number = $request->entry_number;
            $entry->entry_date = $request->entry_date;
            $entry->description = $request->description;
            $entry->reference_type = $request->reference_type;
            $entry->reference_id = $request->reference_id;
            $entry->save();

            // حذف البنود الحالية
            $entry->items()->delete();

            // إنشاء البنود الجديدة
            foreach ($request->items as $itemData) {
                $item = new JournalEntryItem();
                $item->journal_entry_id = $entry->id;
                $item->account_id = $itemData['account_id'];
                $item->debit = floatval($itemData['debit'] ?? 0);
                $item->credit = floatval($itemData['credit'] ?? 0);
                $item->description = $itemData['description'] ?? null;
                $item->save();
            }

            DB::commit();

            return redirect()->route('journal-entries.show', $entry->id)
                ->with('success', 'تم تحديث القيد المحاسبي بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء تحديث القيد المحاسبي: ' . $e->getMessage())
                ->withInput();
        }
    }

    /**
     * حذف قيد محاسبي محدد
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $user = Auth::user();
        $query = JournalEntry::query();

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد غير مرحل وغير معتمد
        if ($entry->is_posted || $entry->is_approved) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'لا يمكن حذف القيد المحاسبي لأنه مرحل أو معتمد');
        }

        DB::beginTransaction();

        try {
            // حذف بنود القيد المحاسبي
            $entry->items()->delete();

            // حذف القيد المحاسبي
            $entry->delete();

            DB::commit();

            return redirect()->route('journal-entries.index')
                ->with('success', 'تم حذف القيد المحاسبي بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء حذف القيد المحاسبي: ' . $e->getMessage());
        }
    }

    /**
     * ترحيل قيد محاسبي محدد
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function post($id)
    {
        $user = Auth::user();
        $query = JournalEntry::with('items.account');

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد غير مرحل
        if ($entry->is_posted) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'القيد المحاسبي مرحل بالفعل');
        }

        DB::beginTransaction();

        try {
            // تحديث أرصدة الحسابات
            foreach ($entry->items as $item) {
                $account = $item->account;

                // تحديث الرصيد الحالي للحساب
                if ($item->debit > 0) {
                    if (in_array($account->account_type, ['asset', 'expense'])) {
                        $account->current_balance += $item->debit;
                    } else {
                        $account->current_balance -= $item->debit;
                    }
                }

                if ($item->credit > 0) {
                    if (in_array($account->account_type, ['asset', 'expense'])) {
                        $account->current_balance -= $item->credit;
                    } else {
                        $account->current_balance += $item->credit;
                    }
                }

                $account->save();
            }

            // تحديث حالة القيد المحاسبي
            $entry->is_posted = true;
            $entry->posted_at = now();
            $entry->posted_by = Auth::id();
            $entry->save();

            // إنشاء كشف حساب للعميل من القيد المحاسبي
            \App\Models\CustomerStatement::createForJournalEntry($entry);

            DB::commit();

            return redirect()->route('journal-entries.show', $entry->id)
                ->with('success', 'تم ترحيل القيد المحاسبي بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء ترحيل القيد المحاسبي: ' . $e->getMessage());
        }
    }

    /**
     * اعتماد قيد محاسبي محدد
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function approve($id)
    {
        $user = Auth::user();
        $query = JournalEntry::query();

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد غير معتمد
        if ($entry->is_approved) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'القيد المحاسبي معتمد بالفعل');
        }

        // تحديث حالة القيد المحاسبي
        $entry->is_approved = true;
        $entry->approved_at = now();
        $entry->approved_by = Auth::id();
        $entry->save();

        return redirect()->route('journal-entries.show', $entry->id)
            ->with('success', 'تم اعتماد القيد المحاسبي بنجاح');
    }

    /**
     * إلغاء ترحيل قيد محاسبي محدد
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function unpost($id)
    {
        $user = Auth::user();
        $query = JournalEntry::with('items.account');

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد مرحل وغير معتمد
        if (!$entry->is_posted) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'القيد المحاسبي غير مرحل');
        }

        if ($entry->is_approved) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'لا يمكن إلغاء ترحيل القيد المحاسبي لأنه معتمد');
        }

        DB::beginTransaction();

        try {
            // إعادة أرصدة الحسابات
            foreach ($entry->items as $item) {
                $account = $item->account;

                // تحديث الرصيد الحالي للحساب (عكس التأثير)
                if ($item->debit > 0) {
                    if (in_array($account->account_type, ['asset', 'expense'])) {
                        $account->current_balance -= $item->debit;
                    } else {
                        $account->current_balance += $item->debit;
                    }
                }

                if ($item->credit > 0) {
                    if (in_array($account->account_type, ['asset', 'expense'])) {
                        $account->current_balance += $item->credit;
                    } else {
                        $account->current_balance -= $item->credit;
                    }
                }

                $account->save();
            }

            // تحديث حالة القيد المحاسبي
            $entry->is_posted = false;
            $entry->posted_at = null;
            $entry->posted_by = null;
            $entry->save();

            // حذف سجلات كشف حساب العميل المرتبطة بهذا القيد
            \App\Models\CustomerStatement::where('reference_type', 'App\\Models\\JournalEntry')
                ->where('reference_id', $entry->id)
                ->delete();

            DB::commit();

            return redirect()->route('journal-entries.show', $entry->id)
                ->with('success', 'تم إلغاء ترحيل القيد المحاسبي بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->with('error', 'حدث خطأ أثناء إلغاء ترحيل القيد المحاسبي: ' . $e->getMessage());
        }
    }

    /**
     * إلغاء اعتماد قيد محاسبي محدد
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function unapprove($id)
    {
        $user = Auth::user();
        $query = JournalEntry::query();

        if (!$user->isSystemAdmin()) {
            $query->where('company_id', $user->company_id);
        }

        $entry = $query->findOrFail($id);

        // التحقق من أن القيد معتمد
        if (!$entry->is_approved) {
            return redirect()->route('journal-entries.show', $entry->id)
                ->with('error', 'القيد المحاسبي غير معتمد');
        }

        // تحديث حالة القيد المحاسبي
        $entry->is_approved = false;
        $entry->approved_at = null;
        $entry->approved_by = null;
        $entry->save();

        return redirect()->route('journal-entries.show', $entry->id)
            ->with('success', 'تم إلغاء اعتماد القيد المحاسبي بنجاح');
    }
}
