<?php

namespace App\Http\Controllers\Accounting;

use App\Http\Controllers\Controller;
use App\Models\AccountingPeriod;
use App\Models\Branch;
use App\Models\ChartOfAccount;
use App\Models\FiscalYear;
use App\Models\JournalDetail;
use App\Models\JournalEntry;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class JournalEntryController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:accounting.journal-entries.view')->only(['index', 'show']);
        $this->middleware('permission:accounting.journal-entries.create')->only(['create', 'store']);
        $this->middleware('permission:accounting.journal-entries.edit')->only(['edit', 'update']);
        $this->middleware('permission:accounting.journal-entries.delete')->only(['destroy']);
        $this->middleware('permission:accounting.journal-entries.post')->only(['post']);
        $this->middleware('permission:accounting.journal-entries.approve')->only(['approve']);
        $this->middleware('permission:accounting.journal-entries.reject')->only(['reject']);
    }

    /**
     * عرض قائمة قيود اليومية
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $companyId = Auth::user()->company_id;
        $entries = JournalEntry::where('company_id', $companyId)
            ->with('fiscalYear', 'accountingPeriod', 'branch', 'creator')
            ->orderBy('entry_date', 'desc')
            ->paginate(15);

        return view('accounting.journal-entries.index', ['entries' => $entries]);
    }

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

        // الحصول على السنة المالية النشطة
        $fiscalYear = FiscalYear::where('company_id', $companyId)
            ->where('status', 'active')
            ->first();

        if (!$fiscalYear) {
            return redirect()->route('accounting.fiscal-years.index')
                ->with('info', 'يجب تنشيط سنة مالية أولاً');
        }

        // الحصول على الفترة المحاسبية المفتوحة الحالية
        $period = $fiscalYear->getCurrentPeriod();

        if (!$period) {
            // البحث عن أي فترة محاسبية مفتوحة
            $period = $fiscalYear->accountingPeriods()
                ->where('status', 'open')
                ->latest('end_date')
                ->first();

            if (!$period) {
                return redirect()->route('accounting.accounting-periods.create')
                    ->with('info', 'يجب إنشاء فترة محاسبية مفتوحة للسنة المالية النشطة قبل إضافة قيود يومية');
            }
        }

        // الحصول على الفروع
        $branches = Branch::where('company_id', $companyId)
            ->where('is_active', true)
            ->get();

        // الحصول على الحسابات النشطة
        $accounts = ChartOfAccount::where('company_id', $companyId)
            ->where('is_active', true)
            ->orderBy('code')
            ->get();

        // أنواع القيود
        $entryTypes = [
            'manual' => 'يدوي',
            'automatic' => 'آلي',
            'recurring' => 'متكرر',
            'adjustment' => 'تسوية'
        ];

        return view('accounting.journal-entries.create', compact(
            'fiscalYear',
            'period',
            'branches',
            'accounts',
            'entryTypes'
        ));
    }

    /**
     * تخزين قيد يومية جديد
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $companyId = Auth::user()->company_id;

        if (!$companyId) {
            abort(403, 'لم يتم تحديد شركة - يرجى تحديث الصفحة');
        }

        $request->validate([
            'fiscal_year_id' => 'required|exists:fiscal_years,id',
            'accounting_period_id' => 'required|exists:accounting_periods,id',
            'branch_id' => 'nullable|exists:branches,id',
            'entry_date' => 'required|date',
            'entry_type' => 'required|in:manual,automatic,recurring,adjustment',
            'description' => 'required|string',
            'notes' => 'nullable|string',
            'accounts' => 'required|array|min:2',
            'accounts.*.account_id' => 'required|exists:chart_of_accounts,id',
            'accounts.*.debit_amount' => 'nullable|numeric|min:0',
            'accounts.*.credit_amount' => 'nullable|numeric|min:0',
            'accounts.*.description' => 'nullable|string',
        ]);

        // التحقق من أن السنة المالية والفترة المحاسبية تنتميان للشركة الحالية
        $fiscalYear = FiscalYear::findOrFail($request->fiscal_year_id);
        $period = AccountingPeriod::findOrFail($request->accounting_period_id);

        if ($fiscalYear->company_id !== $companyId || $period->company_id !== $companyId) {
            abort(403);
        }

        // التحقق من أن الفترة المحاسبية تنتمي للسنة المالية
        if ($period->fiscal_year_id !== $fiscalYear->id) {
            return redirect()->back()
                ->withInput()
                ->withErrors(['accounting_period_id' => 'الفترة المحاسبية لا تنتمي للسنة المالية المحددة']);
        }

        // التحقق من أن الفترة المحاسبية مفتوحة
        if ($period->status !== 'open') {
            return redirect()->back()
                ->withInput()
                ->withErrors(['accounting_period_id' => 'الفترة المحاسبية مغلقة']);
        }

        // التحقق من أن تاريخ القيد يقع ضمن الفترة المحاسبية
        $entryDate = Carbon::parse($request->entry_date)->startOfDay();
        $startDate = $period->start_date->startOfDay();
        $endDate = $period->end_date->startOfDay();
        
        if ($entryDate < $startDate || $entryDate > $endDate) {
            return redirect()->back()
                ->withInput()
                ->withErrors(['entry_date' => 'تاريخ القيد يجب أن يكون ضمن الفترة المحاسبية']);
        }

        // التحقق من أن الفرع ينتمي للشركة الحالية
        if ($request->branch_id) {
            $branch = Branch::findOrFail($request->branch_id);
            if ($branch->company_id !== $companyId) {
                abort(403);
            }
        }

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

        foreach ($request->accounts as $account) {
            $totalDebit += floatval($account['debit_amount'] ?? 0);
            $totalCredit += floatval($account['credit_amount'] ?? 0);
        }

        if (abs($totalDebit - $totalCredit) > 0.01) {
            return redirect()->back()
                ->withInput()
                ->withErrors(['accounts' => 'يجب أن يكون مجموع المدين يساوي مجموع الدائن']);
        }

        // التحقق من أن كل حساب ينتمي للشركة الحالية
        foreach ($request->accounts as $account) {
            $chartAccount = ChartOfAccount::findOrFail($account['account_id']);
            if ($chartAccount->company_id !== $companyId) {
                abort(403);
            }
        }

        // إنشاء رقم مرجعي فريد
        $referenceNumber = 'JE-' . date('Ymd') . '-' . rand(1000, 9999);

        DB::beginTransaction();

        try {
            // إنشاء قيد اليومية
            $entry = new JournalEntry();
            $entry->company_id = $companyId;
            $entry->branch_id = $request->branch_id;
            $entry->fiscal_year_id = $request->fiscal_year_id;
            $entry->accounting_period_id = $request->accounting_period_id;
            $entry->created_by = Auth::id();
            $entry->reference_number = $referenceNumber;
            $entry->entry_date = $request->entry_date;
            $entry->entry_type = $request->entry_type;
            $entry->description = $request->description;
            $entry->notes = $request->notes;
            $entry->total_debit = $totalDebit;
            $entry->total_credit = $totalCredit;
            $entry->status = 'draft';
            $entry->save();

            // إنشاء تفاصيل القيد
            foreach ($request->accounts as $account) {
                $detail = new JournalDetail();
                $detail->company_id = $companyId;
                $detail->journal_entry_id = $entry->id;
                $detail->account_id = $account['account_id'];
                $detail->debit_amount = floatval($account['debit_amount'] ?? 0);
                $detail->credit_amount = floatval($account['credit_amount'] ?? 0);
                $detail->description = $account['description'] ?? null;
                $detail->save();
            }

            DB::commit();

            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('success', 'تم إنشاء قيد اليومية بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->back()
                ->withInput()
                ->with('error', 'حدث خطأ أثناء إنشاء قيد اليومية: ' . $e->getMessage());
        }
    }

    /**
     * عرض قيد يومية محدد
     *
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function show(JournalEntry $entry)
    {
        if ($entry->company_id !== Auth::user()->company_id) {
            abort(403);
        }

        $entry->load('fiscalYear', 'accountingPeriod', 'branch', 'creator', 'approver', 'details.account');

        return view('accounting.journal-entries.show', compact('entry'));
    }

    /**
     * عرض نموذج تعديل قيد يومية
     *
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function edit(JournalEntry $entry)
    {
        $companyId = Auth::user()->company_id;

        if ($entry->company_id !== $companyId) {
            abort(403);
        }

        if (!$entry->canBeEdited()) {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'لا يمكن تعديل القيد في الحالة الحالية');
        }

        $entry->load('details.account');

        // الحصول على الفروع
        $branches = Branch::where('company_id', $companyId)
            ->where('is_active', true)
            ->get();

        // الحصول على الحسابات النشطة
        $accounts = ChartOfAccount::where('company_id', $companyId)
            ->where('is_active', true)
            ->orderBy('code')
            ->get();

        // أنواع القيود
        $entryTypes = [
            'manual' => 'يدوي',
            'automatic' => 'آلي',
            'recurring' => 'متكرر',
            'adjustment' => 'تسوية'
        ];

        return view('accounting.journal-entries.edit', compact(
            'entry',
            'branches',
            'accounts',
            'entryTypes'
        ));
    }

    /**
     * تحديث قيد يومية محدد
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, JournalEntry $entry)
    {
        $companyId = Auth::user()->company_id;

        if ($entry->company_id !== $companyId) {
            abort(403);
        }

        if (!$entry->canBeEdited()) {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'لا يمكن تعديل القيد في الحالة الحالية');
        }

        $request->validate([
            'branch_id' => 'nullable|exists:branches,id',
            'entry_date' => 'required|date',
            'entry_type' => 'required|in:manual,automatic,recurring,adjustment',
            'description' => 'required|string',
            'notes' => 'nullable|string',
            'accounts' => 'required|array|min:2',
            'accounts.*.account_id' => 'required|exists:chart_of_accounts,id',
            'accounts.*.debit_amount' => 'nullable|numeric|min:0',
            'accounts.*.credit_amount' => 'nullable|numeric|min:0',
            'accounts.*.description' => 'nullable|string',
        ]);

        // التحقق من أن تاريخ القيد يقع ضمن الفترة المحاسبية
        $period = $entry->accountingPeriod;
        $entryDate = Carbon::parse($request->entry_date)->startOfDay();
        $startDate = $period->start_date->startOfDay();
        $endDate = $period->end_date->startOfDay();
        
        if ($entryDate < $startDate || $entryDate > $endDate) {
            return redirect()->back()
                ->withInput()
                ->withErrors(['entry_date' => 'تاريخ القيد يجب أن يكون ضمن الفترة المحاسبية']);
        }

        // التحقق من أن الفرع ينتمي للشركة الحالية
        if ($request->branch_id) {
            $branch = Branch::findOrFail($request->branch_id);
            if ($branch->company_id !== $companyId) {
                abort(403);
            }
        }

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

        foreach ($request->accounts as $account) {
            $totalDebit += floatval($account['debit_amount'] ?? 0);
            $totalCredit += floatval($account['credit_amount'] ?? 0);
        }

        if (abs($totalDebit - $totalCredit) > 0.01) {
            return redirect()->back()
                ->withInput()
                ->withErrors(['accounts' => 'يجب أن يكون مجموع المدين يساوي مجموع الدائن']);
        }

        // التحقق من أن كل حساب ينتمي للشركة الحالية
        foreach ($request->accounts as $account) {
            $chartAccount = ChartOfAccount::findOrFail($account['account_id']);
            if ($chartAccount->company_id !== $companyId) {
                abort(403);
            }
        }

        DB::beginTransaction();

        try {
            // تحديث قيد اليومية
            $entry->branch_id = $request->branch_id;
            $entry->entry_date = $request->entry_date;
            $entry->entry_type = $request->entry_type;
            $entry->description = $request->description;
            $entry->notes = $request->notes;
            $entry->total_debit = $totalDebit;
            $entry->total_credit = $totalCredit;
            $entry->save();

            // حذف تفاصيل القيد القديمة
            $entry->details()->delete();

            // إنشاء تفاصيل القيد الجديدة
            foreach ($request->accounts as $account) {
                $detail = new JournalDetail();
                $detail->company_id = $companyId;
                $detail->journal_entry_id = $entry->id;
                $detail->account_id = $account['account_id'];
                $detail->debit_amount = floatval($account['debit_amount'] ?? 0);
                $detail->credit_amount = floatval($account['credit_amount'] ?? 0);
                $detail->description = $account['description'] ?? null;
                $detail->save();
            }

            DB::commit();

            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('success', 'تم تحديث قيد اليومية بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->back()
                ->withInput()
                ->with('error', 'حدث خطأ أثناء تحديث قيد اليومية: ' . $e->getMessage());
        }
    }

    /**
     * ترحيل قيد يومية
     *
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function post(JournalEntry $entry)
    {
        if ($entry->company_id !== Auth::user()->company_id) {
            abort(403);
        }

        // التحقق من إمكانية ترحيل القيد
        if (!$entry->canBePosted()) {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'لا يمكن ترحيل القيد في الحالة الحالية');
        }

        if ($entry->post()) {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('success', 'تم ترحيل قيد اليومية بنجاح');
        } else {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'حدث خطأ أثناء ترحيل قيد اليومية');
        }
    }

    /**
     * اعتماد قيد يومية
     *
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function approve(JournalEntry $entry)
    {
        if ($entry->company_id !== Auth::user()->company_id) {
            abort(403);
        }

        // التحقق من إمكانية اعتماد القيد
        if (!$entry->canBeApproved()) {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'لا يمكن اعتماد القيد في الحالة الحالية');
        }

        $entry->status = 'approved';
        $entry->approved_by = Auth::id();
        $entry->approved_at = now();
        $entry->save();

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

    /**
     * رفض قيد يومية
     *
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function reject(JournalEntry $entry)
    {
        if ($entry->company_id !== Auth::user()->company_id) {
            abort(403);
        }

        // التحقق من إمكانية رفض القيد
        if (!$entry->canBeRejected()) {
            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'لا يمكن رفض القيد في الحالة الحالية');
        }

        $entry->status = 'rejected';
        $entry->save();

        return redirect()->route('accounting.journal-entries.show', $entry)
            ->with('success', 'تم رفض قيد اليومية بنجاح');
    }

    /**
     * حذف قيد يومية محدد
     *
     * @param  \App\Models\JournalEntry  $entry
     * @return \Illuminate\Http\Response
     */
    public function destroy(JournalEntry $entry)
    {
        if ($entry->company_id !== Auth::user()->company_id) {
            abort(403);
        }

        // التحقق من إمكانية حذف القيد
        if (!$entry->canBeDeleted()) {
            if ($entry->isAutomatic()) {
                $sourceModel = $entry->getSourceModel();
                $sourceInfo = '';
                if ($sourceModel) {
                    $sourceType = class_basename($sourceModel);
                    $sourceInfo = " (متولد من مستند {$sourceType})";
                }
                $message = "لا يمكن حذف هذا القيد لأنه متولد من مستند آخر{$sourceInfo}. يرجى تعديل المستند نفسه بدلاً من ذلك.";
                return redirect()->route('accounting.journal-entries.show', $entry)
                    ->with('error', $message);
            } else {
                return redirect()->route('accounting.journal-entries.show', $entry)
                    ->with('error', 'لا يمكن حذف القيد بعد ترحيله');
            }
        }

        DB::beginTransaction();

        try {
            // حذف تفاصيل القيد
            $entry->details()->delete();

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

            DB::commit();

            return redirect()->route('accounting.journal-entries.index')
                ->with('success', 'تم حذف قيد اليومية بنجاح');
        } catch (\Exception $e) {
            DB::rollBack();

            return redirect()->route('accounting.journal-entries.show', $entry)
                ->with('error', 'حدث خطأ أثناء حذف قيد اليومية: ' . $e->getMessage());
        }
    }
}
