<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Expense;
use App\Models\ExpenseCategory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Services\AccountingService;

class AdminExpenseController extends Controller
{
    /**
     * Helper untuk mengambil ID Akun Kas/Bank berdasarkan Branch Mapping
     */
    private function getBranchCashAccount($branchId, $type = 'kas_kecil')
    {
        return DB::table('branch_accounts')
            ->where('branch_id', $branchId)
            ->where('type', $type)
            ->where('is_active', 1) 
            ->value('account_id');
    }

    public function index(Request $request)
    {
        try {
            $user = $request->user();
            if (!$user) {
                return response()->json(['success' => false, 'message' => 'Sesi habis'], 401);
            }

            // PERBAIKAN BUG SUMBER DANA: Tarik akun kas/bank ter-mapping khusus untuk form (Menghindari pembuatan route baru)
            if ($request->has('get_mapped_accounts') && $request->filled('branch_id')) {
                $mappedAccounts = DB::table('branch_accounts')
                    ->join('accounts', 'branch_accounts.account_id', '=', 'accounts.id')
                    ->where('branch_accounts.branch_id', $request->branch_id)
                    ->where('branch_accounts.is_active', 1)
                    ->select('accounts.id', 'accounts.name', 'accounts.code')
                    ->get();
                return response()->json(['success' => true, 'data' => $mappedAccounts]);
            }

            $query = Expense::with(['expenseCategory', 'user', 'branch', 'fundAccount'])
                        ->orderBy('expense_date', 'desc');

            // PERBAIKAN BUG DATA KOSONG: Deteksi role lebih aman (mendukung Spatie maupun kolom langsung)
            $roleName = $user->role ?? ($user->roles->first()->name ?? '');
            $isOwner = in_array(strtolower($roleName), ['owner', 'super_admin']);
            
            if (!$isOwner) {
                $query->where('branch_id', $user->branch_id);
            }

            if ($request->filled('search')) {
                $query->where('name', 'like', "%{$request->search}%");
            }

            if ($request->filled('start_date')) {
                $query->whereDate('expense_date', '>=', $request->start_date);
            }
            if ($request->filled('end_date')) {
                $query->whereDate('expense_date', '<=', $request->end_date);
            }

            if ($request->filled('category_id') && $request->category_id !== 'all') {
                $query->where('expense_category_id', $request->category_id);
            }

            if ($request->filled('fund_account_id') && $request->fund_account_id !== 'all') {
                $query->where('fund_account_id', $request->fund_account_id);
            }

            return response()->json(['success' => true, 'data' => $query->get()]);

        } catch (\Throwable $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function store(Request $request)
    {
        $request->validate([
            'expense_date' => 'required|date',
            'expense_category_id' => 'required|exists:expense_categories,id',
            'name' => 'required|string|max:255',
            'amount' => 'required|numeric|min:1',
            'fund_source' => 'nullable|string', 
            'fund_account_id' => 'nullable|exists:accounts,id', 
            'branch_id' => 'nullable|exists:branches,id',
            'note' => 'nullable|string',
        ]);

        DB::beginTransaction();
        try {
            $user = $request->user();
            
            // PERBAIKAN ROLE CHECK
            $roleName = $user->role ?? ($user->roles->first()->name ?? '');
            $isOwner = in_array(strtolower($roleName), ['owner', 'super_admin']);
            
            $branchId = $isOwner ? ($request->branch_id ?? $user->branch_id) : $user->branch_id;

            if ($request->filled('fund_account_id') && !$isOwner) {
                $isMapped = DB::table('branch_accounts')
                    ->where('branch_id', $branchId)
                    ->where('account_id', $request->fund_account_id)
                    ->where('is_active', 1)
                    ->exists();

                if (!$isMapped) {
                    throw new \Exception('Akses ditolak (Security Lock): Akun Kas/Bank yang Anda pilih belum dipetakan secara resmi untuk wewenang cabang Anda. Silakan hubungi Pusat.');
                }
            }

            $expense = Expense::create([
                'expense_date' => $request->expense_date,
                'expense_category_id' => $request->expense_category_id,
                'name' => $request->name,
                'amount' => $request->amount,
                'fund_source' => $request->fund_source, 
                'fund_account_id' => $request->fund_account_id, 
                'branch_id' => $branchId,
                'user_id' => $user->id,
                'note' => $request->note,
            ]);

            $category = ExpenseCategory::find($request->expense_category_id);
            $debitAccountId = $category->account_id ?? AccountingService::getAccountId('default_expense_account');
            
            $creditAccountId = null;
            if ($request->filled('fund_account_id')) {
                $creditAccountId = $request->fund_account_id;
            } else {
                $mapType = ($request->fund_source === 'drawer') ? 'kas_kecil' : 'bank_operasional';
                $creditAccountId = $this->getBranchCashAccount($branchId, $mapType);
                
                if (!$creditAccountId) {
                    throw new \Exception("Gagal: Rekening Kas/Bank untuk tipe pengeluaran ini ({$mapType}) belum dipetakan untuk cabang Anda. Silakan hubungi Pusat.");
                }
            }

            if ($debitAccountId && $creditAccountId) {
                AccountingService::log([
                    'branch_id'   => $branchId,
                    'entry_date'  => $request->expense_date,
                    'source_type' => 'EXPENSE',
                    'reference'   => (string) $expense->id,
                    'description' => "Biaya: {$request->name} ({$category->name})",
                    'user_id'     => $user->id,
                    'items'       => [
                        ['account_id' => $debitAccountId, 'debit' => $request->amount, 'credit' => 0],
                        ['account_id' => $creditAccountId, 'debit' => 0, 'credit' => $request->amount]
                    ]
                ]);
            }

            DB::commit();
            return response()->json(['success' => true, 'message' => 'Pengeluaran dicatat & dijurnal!', 'data' => $expense]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function update(Request $request, $id)
    {
        $request->validate([
            'expense_date' => 'required|date',
            'expense_category_id' => 'required|exists:expense_categories,id',
            'name' => 'required|string|max:255',
            'amount' => 'required|numeric|min:1',
            'fund_account_id' => 'nullable|exists:accounts,id', 
            'branch_id' => 'nullable|exists:branches,id',
            'note' => 'nullable|string',
        ]);

        DB::beginTransaction();
        try {
            $user = $request->user();
            $expense = Expense::findOrFail($id);
            
            // PERBAIKAN ROLE CHECK
            $roleName = $user->role ?? ($user->roles->first()->name ?? '');
            $isOwner = in_array(strtolower($roleName), ['owner', 'super_admin']);

            if (!$isOwner && $expense->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: Anda tidak memiliki hak akses untuk mengubah pengeluaran cabang lain.');
            }

            $branchId = $isOwner ? ($request->branch_id ?? $expense->branch_id) : $user->branch_id;

            if ($request->filled('fund_account_id') && !$isOwner) {
                $isMapped = DB::table('branch_accounts')
                    ->where('branch_id', $branchId)
                    ->where('account_id', $request->fund_account_id)
                    ->where('is_active', 1)
                    ->exists();

                if (!$isMapped) {
                    throw new \Exception('Akses ditolak (Security Lock): Akun Kas/Bank yang Anda pilih belum dipetakan secara resmi untuk wewenang cabang Anda. Silakan hubungi Pusat.');
                }
            }

            $glHeader = DB::table('journal_entries')
                ->where('source_type', 'EXPENSE')
                ->where('reference', (string) $expense->id)
                ->first();

            if ($glHeader) {
                DB::table('journal_items')->where('journal_entry_id', $glHeader->id)->delete();
                DB::table('journal_entries')->where('id', $glHeader->id)->delete();
            }

            $expense->update([
                'expense_date' => $request->expense_date,
                'expense_category_id' => $request->expense_category_id,
                'name' => $request->name,
                'amount' => $request->amount,
                'fund_account_id' => $request->fund_account_id, 
                'branch_id' => $branchId,
                'note' => $request->note,
            ]);

            $category = ExpenseCategory::find($request->expense_category_id);
            $debitAccountId = $category->account_id ?? AccountingService::getAccountId('default_expense_account');
            
            $creditAccountId = null;
            if ($request->filled('fund_account_id')) {
                $creditAccountId = $request->fund_account_id;
            } else {
                $mapType = ($expense->fund_source === 'drawer') ? 'kas_kecil' : 'bank_operasional';
                $creditAccountId = $this->getBranchCashAccount($branchId, $mapType);
                
                if (!$creditAccountId) {
                    throw new \Exception("Gagal: Rekening Kas/Bank untuk tipe pengeluaran ini ({$mapType}) belum dipetakan untuk cabang Anda. Silakan hubungi Pusat.");
                }
            }

            if ($debitAccountId && $creditAccountId) {
                AccountingService::log([
                    'branch_id'   => $branchId,
                    'entry_date'  => $request->expense_date,
                    'source_type' => 'EXPENSE',
                    'reference'   => (string) $expense->id,
                    'description' => "Biaya (Revisi): {$request->name} ({$category->name})",
                    'user_id'     => $user->id,
                    'items'       => [
                        ['account_id' => $debitAccountId, 'debit' => $request->amount, 'credit' => 0],
                        ['account_id' => $creditAccountId, 'debit' => 0, 'credit' => $request->amount]
                    ]
                ]);
            }

            DB::commit();
            return response()->json(['success' => true, 'message' => 'Pengeluaran & jurnal diperbarui!', 'data' => $expense]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function destroy($id)
    {
        DB::beginTransaction();
        try {
            $user = request()->user();
            $expense = Expense::findOrFail($id);
            
            // PERBAIKAN ROLE CHECK
            $roleName = $user->role ?? ($user->roles->first()->name ?? '');
            $isOwner = in_array(strtolower($roleName), ['owner', 'super_admin']);

            if ($user && !$isOwner && $expense->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: Anda tidak memiliki hak akses untuk menghapus pengeluaran cabang lain.');
            }

            $glHeader = DB::table('journal_entries')
                ->where('source_type', 'EXPENSE')
                ->where('reference', (string) $expense->id)
                ->first();

            if ($glHeader) {
                DB::table('journal_items')->where('journal_entry_id', $glHeader->id)->delete();
                DB::table('journal_entries')->where('id', $glHeader->id)->delete();
            }

            $expense->delete();

            DB::commit();
            return response()->json(['success' => true, 'message' => 'Data pengeluaran dan jurnal dihapus!']);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['success' => false, 'message' => 'Gagal menghapus data: ' . $e->getMessage()], 500);
        }
    }
}