<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Helpers\RestaurantBranchFilterTrait;
use App\Models\DailyClosingReport;
use App\Models\PosOrder;
use App\Models\Expense;
use App\Models\Branch;
use App\Models\EmployeeWalletTransaction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class DailyClosingReportController extends Controller
{
    use RestaurantBranchFilterTrait;

    public function __construct()
    {
        $this->middleware('auth:sanctum');
    }

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $user = $request->user();

        // Access control
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $query = DailyClosingReport::with(['branch', 'restaurant', 'creator', 'updater']);

        // Apply restaurant/branch filtering
        $this->applyRestaurantBranchFilter($query, $user, $request);

        // Date filters
        if ($request->has('date_from') && $request->date_from) {
            $query->whereDate('closing_date', '>=', $request->date_from);
        }

        if ($request->has('date_to') && $request->date_to) {
            $query->whereDate('closing_date', '<=', $request->date_to);
        }

        // Filter by specific date
        if ($request->has('date') && $request->date) {
            $query->whereDate('closing_date', $request->date);
        }

        // Order by date descending
        $perPage = $request->get('per_page', 50);
        $reports = $query->orderBy('closing_date', 'desc')
            ->orderBy('created_at', 'desc')
            ->paginate($perPage);

        return response()->json($reports);
    }

    /**
     * Calculate amounts for a given date and branch
     */
    private function writeLog($method, $message, $data = [])
    {
        $logPath = storage_path('logs/daily_closing_debug.log');
        $logEntry = [
            'timestamp' => now()->toDateTimeString(),
            'method' => $method,
            'message' => $message,
            'data' => $data,
        ];
        @file_put_contents($logPath, json_encode($logEntry) . "\n", FILE_APPEND | LOCK_EX);
    }

    public function calculateAmounts(Request $request)
    {
        $user = $request->user();
        $this->writeLog('calculateAmounts', 'Method called', [
            'user_id' => $user->id ?? null,
            'user_role' => $user->role ?? null,
            'request_data' => $request->all(),
        ]);

        // Access control
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            $this->writeLog('calculateAmounts', 'Unauthorized access', ['user_role' => $user->role ?? null]);
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Convert empty strings to null for time fields before validation
        $requestData = $request->all();
        $originalStartTime = $requestData['start_time'] ?? null;
        $originalEndTime = $requestData['end_time'] ?? null;
        
        if (isset($requestData['start_time']) && $requestData['start_time'] === '') {
            $requestData['start_time'] = null;
            $this->writeLog('calculateAmounts', 'Converted empty start_time to null', ['original' => $originalStartTime]);
        }
        if (isset($requestData['end_time']) && $requestData['end_time'] === '') {
            $requestData['end_time'] = null;
            $this->writeLog('calculateAmounts', 'Converted empty end_time to null', ['original' => $originalEndTime]);
        }
        $request->merge($requestData);
        
        $this->writeLog('calculateAmounts', 'After time field conversion', [
            'start_time' => $requestData['start_time'] ?? null,
            'end_time' => $requestData['end_time'] ?? null,
        ]);

        try {
            $validated = $request->validate([
                'date' => 'required|date', // Required for backward compatibility, but will use start_date/end_date if provided
                'branch_id' => 'required|exists:branches,id',
                'start_date' => 'nullable|date',
                'start_time' => 'nullable|date_format:H:i',
                'end_date' => 'nullable|date',
                'end_time' => 'nullable|date_format:H:i',
            ]);
            $this->writeLog('calculateAmounts', 'Validation passed', ['validated' => $validated]);
        } catch (\Illuminate\Validation\ValidationException $e) {
            $this->writeLog('calculateAmounts', 'Validation failed', [
                'errors' => $e->errors(),
                'request_data' => $request->all(),
            ]);
            throw $e;
        }

        $branchId = $validated['branch_id'];
        $date = Carbon::parse($validated['date'])->format('Y-m-d');
        
        // Determine date/time range
        if (!empty($validated['start_date']) && !empty($validated['end_date'])) {
            // Use provided date/time range
            $startDate = Carbon::parse($validated['start_date']);
            if (!empty($validated['start_time'])) {
                $startTime = Carbon::parse($validated['start_time']);
                $startDate->setTime($startTime->hour, $startTime->minute, $startTime->second);
            } else {
                $startDate->startOfDay();
            }
            
            $endDate = Carbon::parse($validated['end_date']);
            if (!empty($validated['end_time'])) {
                $endTime = Carbon::parse($validated['end_time']);
                $endDate->setTime($endTime->hour, $endTime->minute, $endTime->second);
                
                // Handle case where end_time is earlier in the day than start_time (crossing midnight)
                // Check if end date/time is actually before start date/time
                // If so, add 1 day to end_date to handle midnight crossing
                $tempEndDate = $endDate->copy();
                if ($tempEndDate->lte($startDate)) {
                    // End date/time is before or equal to start date/time, add 1 day
                    $endDate->addDay();
                    $this->writeLog('calculateAmounts', 'End date/time is before start date/time - adding 1 day to end date for midnight crossing', [
                        'start_date' => $startDate->format('Y-m-d H:i:s'),
                        'end_time' => $endTime->format('H:i'),
                        'original_end_date' => $validated['end_date'],
                        'adjusted_end_date' => $endDate->format('Y-m-d H:i:s'),
                    ]);
                }
            } else {
                $endDate->endOfDay();
            }
            
            // Final validation that start date/time is before end date/time
            if ($endDate->lte($startDate)) {
                $this->writeLog('calculateAmounts', 'End date/time must be after start date/time', [
                    'start_date' => $startDate->format('Y-m-d H:i:s'),
                    'end_date' => $endDate->format('Y-m-d H:i:s'),
                ]);
                return response()->json(['error' => 'End date/time must be after start date/time'], 422);
            }
            
            $this->writeLog('calculateAmounts', 'Date/time range determined', [
                'start_date' => $startDate->format('Y-m-d H:i:s'),
                'end_date' => $endDate->format('Y-m-d H:i:s'),
                'duration_hours' => $startDate->diffInHours($endDate),
            ]);
        } else {
            // No custom range: use order day (orders_date column) for order amounts
            $startDate = Carbon::parse($date)->startOfDay();
            $endDate = Carbon::parse($date)->endOfDay();
        }

        $useOrdersDate = empty($validated['start_date']) || empty($validated['end_date']);

        // Verify branch access
        $branch = Branch::findOrFail($branchId);
        
        if (!$user->isAdmin()) {
            if ($user->isRestaurantOwner() && $branch->restaurant_id != $user->restaurant_id) {
                return response()->json(['error' => 'You can only calculate reports for your restaurant branches'], 403);
            }
            
            if ($user->isBranchManager() && $branch->id != $user->branch_id) {
                return response()->json(['error' => 'You can only calculate reports for your branch'], 403);
            }
        }

        $orderDateFilter = $useOrdersDate
            ? function ($q) use ($date) { $q->where('orders_date', $date); }
            : function ($q) use ($startDate, $endDate) { $q->whereBetween('created_at', [$startDate->toDateTimeString(), $endDate->toDateTimeString()]); };

        // Calculate Gross Sales (sum of grand_total from pos_orders for the date/time range or order day)
        $grossSalesQuery = PosOrder::where('branch_id', $branchId)
            ->whereNull('deleted_at')
            ->where('status', 'paid');
        $orderDateFilter($grossSalesQuery);
        $grossSales = $grossSalesQuery->sum('grand_total');

        $orderCountQuery = PosOrder::where('branch_id', $branchId)
            ->whereNull('deleted_at')
            ->where('status', 'paid');
        $orderDateFilter($orderCountQuery);
        $orderCount = $orderCountQuery->count();

        $this->writeLog('calculateAmounts', 'Gross sales calculation', [
            'branch_id' => $branchId,
            'use_orders_date' => $useOrdersDate,
            'date' => $date,
            'start_date' => $startDate->toDateTimeString(),
            'end_date' => $endDate->toDateTimeString(),
            'gross_sales' => $grossSales,
            'order_count' => $orderCount,
        ]);

        // Calculate Online/Card Payments (payment_mode != 'cash') - only from paid orders
        $onlineCardPaymentsQuery = PosOrder::where('branch_id', $branchId)
            ->whereNull('deleted_at')
            ->where('status', 'paid')
            ->where('payment_mode', '!=', 'cash');
        $orderDateFilter($onlineCardPaymentsQuery);
        $onlineCardPayments = $onlineCardPaymentsQuery->sum('grand_total');

        // Calculate Food Bills (is_food_bill = true) - only from paid orders
        $foodBillsQuery = PosOrder::where('branch_id', $branchId)
            ->whereNull('deleted_at')
            ->where('status', 'paid')
            ->where('is_food_bill', true);
        $orderDateFilter($foodBillsQuery);
        $foodBillsTotal = $foodBillsQuery->sum('grand_total');

        // Calculate Expenses (from expenses table for the date range)
        // Use date range from start to end date (inclusive)
        $expensesPaid = Expense::where('branch_id', $branchId)
            ->whereBetween('expense_date', [
                $startDate->format('Y-m-d'),
                $endDate->format('Y-m-d')
            ])
            ->sum('amount');

        // Calculate Advance Payments from employee_wallet_transactions
        // Advance payments: payment_type = 'advance' and transaction_type = 'credit'
        $advancePayments = EmployeeWalletTransaction::where('branch_id', $branchId)
            ->whereBetween('created_at', [
                $startDate->toDateTimeString(),
                $endDate->toDateTimeString()
            ])
            ->where('payment_type', 'advance')
            ->where('transaction_type', 'credit')
            ->sum('amount');

        // Calculate Daily Wages from employee_wallet_transactions
        // Daily wages: payment_type = 'daily_wage' and transaction_type = 'debit'
        $dailyWages = EmployeeWalletTransaction::where('branch_id', $branchId)
            ->whereBetween('created_at', [
                $startDate->toDateTimeString(),
                $endDate->toDateTimeString()
            ])
            ->where('payment_type', 'daily_wage')
            ->where('transaction_type', 'debit')
            ->sum('amount');

        // Total deductions
        $totalDeductions = $onlineCardPayments + $foodBillsTotal + $expensesPaid + $advancePayments + $dailyWages;

        // Remaining cash
        $remainingCash = $grossSales - $totalDeductions;

        return response()->json([
            'gross_sales' => round($grossSales, 2),
            'online_card_payments' => round($onlineCardPayments, 2),
            'food_bills_total' => round($foodBillsTotal, 2),
            'expenses_paid' => round($expensesPaid, 2),
            'advance_payments' => round($advancePayments, 2),
            'daily_wages' => round($dailyWages, 2),
            'total_deductions' => round($totalDeductions, 2),
            'remaining_cash' => round($remainingCash, 2),
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $user = $request->user();
        $this->writeLog('store', 'Method called', [
            'user_id' => $user->id ?? null,
            'user_role' => $user->role ?? null,
            'request_data' => $request->all(),
        ]);

        // Access control
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            $this->writeLog('store', 'Unauthorized access', ['user_role' => $user->role ?? null]);
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Follow standard pattern to determine restaurant_id and branch_id
        $restaurantId = null;
        $branchId = null;

        if ($user->role === 'admin') {
            $restaurantId = $request->input('restaurant_id');
            $branchId = $request->input('branch_id');
            
            $this->writeLog('store', 'Admin role - getting from request', [
                'restaurant_id' => $restaurantId,
                'branch_id' => $branchId,
            ]);
            
            if (!$restaurantId || !$branchId) {
                $this->writeLog('store', 'Admin missing restaurant_id or branch_id', [
                    'restaurant_id' => $restaurantId,
                    'branch_id' => $branchId,
                ]);
                return response()->json(['error' => 'Restaurant and branch selection required for admin'], 400);
            }
        } elseif ($user->role === 'restaurant_owner') {
            $restaurantId = $user->restaurant_id;
            $branchId = $request->input('branch_id');
            
            $this->writeLog('store', 'Restaurant owner role', [
                'user_restaurant_id' => $restaurantId,
                'request_branch_id' => $branchId,
            ]);
            
            if (!$branchId) {
                $this->writeLog('store', 'Restaurant owner missing branch_id', ['branch_id' => $branchId]);
                return response()->json(['error' => 'Branch selection required'], 400);
            }
            
            if (!$restaurantId) {
                $this->writeLog('store', 'Restaurant owner not assigned to restaurant', ['user_restaurant_id' => $restaurantId]);
                return response()->json(['error' => 'Restaurant owner must be assigned to a restaurant'], 403);
            }
        } elseif ($user->role === 'branch_manager') {
            $restaurantId = $user->restaurant_id;
            $branchId = $user->branch_id;
            
            $this->writeLog('store', 'Branch manager role', [
                'user_restaurant_id' => $restaurantId,
                'user_branch_id' => $branchId,
            ]);
            
            if (!$branchId) {
                $this->writeLog('store', 'Branch manager not assigned to branch', ['user_branch_id' => $branchId]);
                return response()->json(['error' => 'Branch manager must be assigned to a branch'], 403);
            }
        }
        
        $this->writeLog('store', 'Determined restaurant_id and branch_id', [
            'restaurant_id' => $restaurantId,
            'branch_id' => $branchId,
        ]);

        // Verify branch belongs to restaurant (for admin and restaurant owner)
        if ($user->role === 'admin' || $user->role === 'restaurant_owner') {
            $branch = Branch::find($branchId);
            if (!$branch) {
                $this->writeLog('store', 'Branch not found', ['branch_id' => $branchId]);
                return response()->json(['error' => 'Branch not found'], 404);
            }
            
            $this->writeLog('store', 'Branch found', [
                'branch_id' => $branch->id,
                'branch_restaurant_id' => $branch->restaurant_id,
                'expected_restaurant_id' => $restaurantId,
            ]);
            
            if ($user->role === 'restaurant_owner' && $branch->restaurant_id != $restaurantId) {
                $this->writeLog('store', 'Branch does not belong to restaurant owner', [
                    'branch_restaurant_id' => $branch->restaurant_id,
                    'user_restaurant_id' => $restaurantId,
                ]);
                return response()->json(['error' => 'Branch does not belong to your restaurant'], 403);
            }
            
            if ($user->role === 'admin' && $restaurantId && $branch->restaurant_id != $restaurantId) {
                $this->writeLog('store', 'Branch does not belong to selected restaurant', [
                    'branch_restaurant_id' => $branch->restaurant_id,
                    'selected_restaurant_id' => $restaurantId,
                ]);
                return response()->json(['error' => 'Branch does not belong to selected restaurant'], 403);
            }
        }

        // Get branch for restaurant_id
        $branch = Branch::findOrFail($branchId);
        $this->writeLog('store', 'Branch loaded', [
            'branch_id' => $branch->id,
            'branch_restaurant_id' => $branch->restaurant_id,
        ]);

        // Convert empty strings to null for time fields before validation
        $requestData = $request->all();
        $originalStartTime = $requestData['start_time'] ?? null;
        $originalEndTime = $requestData['end_time'] ?? null;
        
        if (isset($requestData['start_time']) && $requestData['start_time'] === '') {
            $requestData['start_time'] = null;
            $this->writeLog('store', 'Converted empty start_time to null', ['original' => $originalStartTime]);
        }
        if (isset($requestData['end_time']) && $requestData['end_time'] === '') {
            $requestData['end_time'] = null;
            $this->writeLog('store', 'Converted empty end_time to null', ['original' => $originalEndTime]);
        }
        $request->merge($requestData);
        
        $this->writeLog('store', 'After time field conversion', [
            'start_time' => $requestData['start_time'] ?? null,
            'end_time' => $requestData['end_time'] ?? null,
        ]);

        try {
            $validated = $request->validate([
                'closing_date' => 'required|date',
                'start_date' => 'nullable|date',
                'start_time' => 'nullable|date_format:H:i',
                'end_date' => 'nullable|date',
                'end_time' => 'nullable|date_format:H:i',
                'available_cash' => 'required|numeric|min:0',
                'gross_sales' => 'nullable|numeric|min:0',
                'online_card_payments' => 'nullable|numeric|min:0',
                'food_bills_total' => 'nullable|numeric|min:0',
                'expenses_paid' => 'nullable|numeric|min:0',
                'advance_payments' => 'nullable|numeric|min:0',
                'daily_wages' => 'nullable|numeric|min:0',
                'comments' => 'nullable|string|max:1000',
            ]);
            $this->writeLog('store', 'Validation passed', ['validated' => $validated]);
        } catch (\Illuminate\Validation\ValidationException $e) {
            $this->writeLog('store', 'Validation failed', [
                'errors' => $e->errors(),
                'request_data' => $request->all(),
            ]);
            throw $e;
        }

        $date = Carbon::parse($validated['closing_date'])->format('Y-m-d');

        // Validate date/time range if provided
        if (!empty($validated['start_date']) && !empty($validated['end_date'])) {
            $startDateTime = Carbon::parse($validated['start_date']);
            if (!empty($validated['start_time'])) {
                $startTime = Carbon::parse($validated['start_time']);
                $startDateTime->setTime($startTime->hour, $startTime->minute, $startTime->second);
            } else {
                $startDateTime->startOfDay();
            }
            
            $endDateTime = Carbon::parse($validated['end_date']);
            if (!empty($validated['end_time'])) {
                $endTime = Carbon::parse($validated['end_time']);
                $endDateTime->setTime($endTime->hour, $endTime->minute, $endTime->second);
                
                // Handle case where end_time is earlier in the day than start_time (crossing midnight)
                // Check if end date/time is actually before start date/time
                // If so, add 1 day to end_date to handle midnight crossing
                $tempEndDateTime = $endDateTime->copy();
                if ($tempEndDateTime->lte($startDateTime)) {
                    // End date/time is before or equal to start date/time, add 1 day
                    $endDateTime->addDay();
                    $this->writeLog('store', 'End date/time is before start date/time - adding 1 day to end date for midnight crossing', [
                        'start_date' => $startDateTime->format('Y-m-d H:i:s'),
                        'end_time' => $endTime->format('H:i'),
                        'original_end_date' => $validated['end_date'],
                        'adjusted_end_date' => $endDateTime->format('Y-m-d H:i:s'),
                    ]);
                }
            } else {
                $endDateTime->endOfDay();
            }
            
            // Final validation that start date/time is before end date/time
            if ($endDateTime->lte($startDateTime)) {
                $this->writeLog('store', 'End date/time must be after start date/time', [
                    'start_date' => $startDateTime->format('Y-m-d H:i:s'),
                    'end_date' => $endDateTime->format('Y-m-d H:i:s'),
                ]);
                return response()->json(['error' => 'End date/time must be after start date/time'], 422);
            }
            
            $this->writeLog('store', 'Date/time range validated', [
                'start_date' => $startDateTime->format('Y-m-d H:i:s'),
                'end_date' => $endDateTime->format('Y-m-d H:i:s'),
                'duration_hours' => $startDateTime->diffInHours($endDateTime),
            ]);
        }

        // Get branch for restaurant_id
        $branch = Branch::findOrFail($branchId);

        // Check if report already exists for this date and branch
        $existingReport = DailyClosingReport::where('branch_id', $branchId)
            ->whereDate('closing_date', $date)
            ->first();

        if ($existingReport) {
            return response()->json(['error' => 'A report already exists for this date and branch'], 422);
        }

        // Determine date/time range for calculations
        if (!empty($validated['start_date']) && !empty($validated['end_date'])) {
            $dateStart = $startDateTime;
            $dateEnd = $endDateTime;
        } else {
            // Fallback to closing_date
            $dateStart = Carbon::parse($date)->startOfDay();
            $dateEnd = Carbon::parse($date)->endOfDay();
        }

        // Calculate amounts if not provided, otherwise use provided values
        // Only include paid, non-deleted orders
        $grossSales = isset($validated['gross_sales']) && $validated['gross_sales'] !== null
            ? $validated['gross_sales']
            : round(PosOrder::where('branch_id', $branchId)
                ->whereNull('deleted_at')
                ->where('status', 'paid')
                ->whereBetween('created_at', [
                    $dateStart->toDateTimeString(),
                    $dateEnd->toDateTimeString()
                ])
                ->sum('grand_total'), 2);

        $onlineCardPayments = isset($validated['online_card_payments']) && $validated['online_card_payments'] !== null
            ? $validated['online_card_payments']
            : round(PosOrder::where('branch_id', $branchId)
                ->whereNull('deleted_at')
                ->where('status', 'paid')
                ->whereBetween('created_at', [
                    $dateStart->toDateTimeString(),
                    $dateEnd->toDateTimeString()
                ])
                ->where('payment_mode', '!=', 'cash')
                ->sum('grand_total'), 2);

        $foodBillsTotal = isset($validated['food_bills_total']) && $validated['food_bills_total'] !== null
            ? $validated['food_bills_total']
            : round(PosOrder::where('branch_id', $branchId)
                ->whereNull('deleted_at')
                ->where('status', 'paid')
                ->whereBetween('created_at', [
                    $dateStart->toDateTimeString(),
                    $dateEnd->toDateTimeString()
                ])
                ->where('is_food_bill', true)
                ->sum('grand_total'), 2);

        $expensesPaid = isset($validated['expenses_paid']) && $validated['expenses_paid'] !== null
            ? $validated['expenses_paid']
            : round(Expense::where('branch_id', $branchId)
                ->whereBetween('expense_date', [$dateStart->format('Y-m-d'), $dateEnd->format('Y-m-d')])
                ->sum('amount'), 2);

        $advancePayments = isset($validated['advance_payments']) && $validated['advance_payments'] !== null
            ? $validated['advance_payments']
            : round(EmployeeWalletTransaction::where('branch_id', $branchId)
                ->whereBetween('created_at', [$dateStart, $dateEnd])
                ->where('payment_type', 'advance')
                ->where('transaction_type', 'credit')
                ->sum('amount'), 2);

        $dailyWages = isset($validated['daily_wages']) && $validated['daily_wages'] !== null
            ? $validated['daily_wages']
            : round(EmployeeWalletTransaction::where('branch_id', $branchId)
                ->whereBetween('created_at', [$dateStart, $dateEnd])
                ->where('payment_type', 'daily_wage')
                ->where('transaction_type', 'debit')
                ->sum('amount'), 2);

        $totalDeductions = $onlineCardPayments + $foodBillsTotal + $expensesPaid + $advancePayments + $dailyWages;
        $remainingCash = $grossSales - $totalDeductions;
        $difference = $remainingCash - $validated['available_cash'];
        $hasDifference = abs($difference) > 0.01; // Consider differences less than 0.01 as no difference

        $report = DailyClosingReport::create([
            'restaurant_id' => $branch->restaurant_id,
            'branch_id' => $branchId,
            'closing_date' => $date,
            'start_date' => $validated['start_date'] ?? null,
            'start_time' => $validated['start_time'] ?? null,
            'end_date' => $validated['end_date'] ?? null,
            'end_time' => $validated['end_time'] ?? null,
            'available_cash' => $validated['available_cash'],
            'gross_sales' => $grossSales,
            'online_card_payments' => $onlineCardPayments,
            'food_bills_total' => $foodBillsTotal,
            'expenses_paid' => $expensesPaid,
            'advance_payments' => $advancePayments,
            'daily_wages' => $dailyWages,
            'total_deductions' => round($totalDeductions, 2),
            'remaining_cash' => round($remainingCash, 2),
            'difference' => round($difference, 2),
            'has_difference' => $hasDifference,
            'comments' => $validated['comments'] ?? null,
            'created_by' => $user->id,
        ]);

        $report->load(['branch', 'restaurant', 'creator']);

        return response()->json($report, 201);
    }

    /**
     * Display the specified resource.
     */
    public function show($id)
    {
        $user = request()->user();
        
        // Get the report ID from route parameter
        $reportId = request()->route('id') ?? $id;
        
        $this->writeLog('show', 'Method called', [
            'user_id' => $user->id ?? null,
            'user_role' => $user->role ?? null,
            'route_id' => $reportId,
            'method_id' => $id,
        ]);
        
        // Find the report
        $dailyClosingReport = DailyClosingReport::find($reportId);
        
        if (!$dailyClosingReport) {
            $this->writeLog('show', 'Report not found', ['report_id' => $reportId]);
            return response()->json(['error' => 'Report not found'], 404);
        }
        
        $this->writeLog('show', 'Report found', [
            'report_id' => $dailyClosingReport->id,
            'report_branch_id' => $dailyClosingReport->branch_id,
            'report_restaurant_id' => $dailyClosingReport->restaurant_id,
        ]);

        // Access control
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Follow standard pattern to determine restaurant_id and branch_id
        $restaurantId = null;
        $branchId = null;

        if ($user->role === 'admin') {
            $restaurantId = request()->input('restaurant_id');
            $branchId = request()->input('branch_id');
            // Admin can view any report, but we still verify access
        } elseif ($user->role === 'restaurant_owner') {
            $restaurantId = $user->restaurant_id;
            $branchId = request()->input('branch_id');
            
            if (!$restaurantId) {
                return response()->json(['error' => 'Restaurant owner must be assigned to a restaurant'], 403);
            }
        } elseif ($user->role === 'branch_manager') {
            $restaurantId = $user->restaurant_id;
            $branchId = $user->branch_id;
            
            if (!$branchId) {
                return response()->json(['error' => 'Branch manager must be assigned to a branch'], 403);
            }
        }

        // Refresh report model to ensure we have latest data
        $dailyClosingReport->refresh();
        
        // Fetch report's branch_id and restaurant_id from database
        $reportBranchId = \DB::table('daily_closing_reports')
            ->where('id', $dailyClosingReport->id)
            ->value('branch_id');
        
        $reportRestaurantId = \DB::table('daily_closing_reports')
            ->where('id', $dailyClosingReport->id)
            ->value('restaurant_id');
        
        $this->writeLog('show', 'Fetched report IDs from database', [
            'report_id' => $dailyClosingReport->id,
            'db_branch_id' => $reportBranchId,
            'db_restaurant_id' => $reportRestaurantId,
            'model_branch_id' => $dailyClosingReport->branch_id,
            'model_restaurant_id' => $dailyClosingReport->restaurant_id,
        ]);
        
        // Fallback to model attributes if database query didn't return values
        if ($reportBranchId === null) {
            $reportBranchId = $dailyClosingReport->branch_id;
            $this->writeLog('show', 'Using model branch_id as fallback', ['branch_id' => $reportBranchId]);
        }
        if ($reportRestaurantId === null) {
            $reportRestaurantId = $dailyClosingReport->restaurant_id;
            $this->writeLog('show', 'Using model restaurant_id as fallback', ['restaurant_id' => $reportRestaurantId]);
        }

        // Verify access based on user role
        if ($user->role === 'admin') {
            // Admin: can view all reports (no additional check needed)
            $this->writeLog('show', 'Admin access granted');
        } elseif ($user->role === 'restaurant_owner') {
            // Restaurant owner: can view reports for any branch under their restaurant
            $this->writeLog('show', 'Checking restaurant owner access', [
                'report_restaurant_id' => $reportRestaurantId,
                'user_restaurant_id' => $restaurantId,
                'match' => ($reportRestaurantId !== null && (int)$reportRestaurantId === (int)$restaurantId),
            ]);
            
            if ($reportRestaurantId === null || (int)$reportRestaurantId !== (int)$restaurantId) {
                $this->writeLog('show', 'Restaurant owner access denied', [
                    'report_restaurant_id' => $reportRestaurantId,
                    'user_restaurant_id' => $restaurantId,
                ]);
                return response()->json(['error' => 'You can only view reports for your restaurant branches'], 403);
            }
            $this->writeLog('show', 'Restaurant owner access granted');
        } elseif ($user->role === 'branch_manager') {
            // Branch manager: can only view reports for their own branch
            $this->writeLog('show', 'Checking branch manager access', [
                'report_id' => $dailyClosingReport->id,
                'report_branch_id' => $reportBranchId,
                'user_branch_id' => $branchId,
                'model_branch_id' => $dailyClosingReport->branch_id,
            ]);
            
            // Check if report has a branch_id
            if ($reportBranchId === null || $reportBranchId === '') {
                // Try to get from model as fallback
                $reportBranchId = $dailyClosingReport->branch_id;
                
                if ($reportBranchId === null || $reportBranchId === '') {
                    $this->writeLog('show', 'Report branch not found', [
                        'report_id' => $dailyClosingReport->id,
                        'db_branch_id' => $reportBranchId,
                        'model_branch_id' => $dailyClosingReport->branch_id,
                    ]);
                    return response()->json(['error' => 'Report branch not found'], 403);
                }
            }
            
            $userBranchId = (int)$branchId;
            $reportBranchIdInt = (int)$reportBranchId;
            
            $this->writeLog('show', 'Branch ID comparison', [
                'user_branch_id' => $userBranchId,
                'report_branch_id' => $reportBranchIdInt,
                'match' => ($reportBranchIdInt === $userBranchId),
            ]);
            
            if ($reportBranchIdInt !== $userBranchId) {
                $this->writeLog('show', 'Branch manager access denied', [
                    'user_branch_id' => $userBranchId,
                    'report_branch_id' => $reportBranchIdInt,
                ]);
                return response()->json(['error' => 'You can only view reports for your branch'], 403);
            }
            $this->writeLog('show', 'Branch manager access granted');
        } else {
            $this->writeLog('show', 'Unauthorized role', ['user_role' => $user->role]);
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Load relationships - this ensures all data is available
        $dailyClosingReport->load(['branch', 'restaurant', 'creator', 'updater']);
        
        // Use the refreshed model instance
        $reportData = $dailyClosingReport;

        // Determine date/time range for fetching related data
        if ($reportData->start_date && $reportData->end_date) {
            $startDate = Carbon::parse($reportData->start_date);
            if ($reportData->start_time) {
                $startTime = Carbon::parse($reportData->start_time);
                $startDate->setTime($startTime->hour, $startTime->minute, $startTime->second);
            } else {
                $startDate->startOfDay();
            }
            
            $endDate = Carbon::parse($reportData->end_date);
            if ($reportData->end_time) {
                $endTime = Carbon::parse($reportData->end_time);
                $endDate->setTime($endTime->hour, $endTime->minute, $endTime->second);
            } else {
                $endDate->endOfDay();
            }
        } else {
            // Fallback to closing_date
            $startDate = Carbon::parse($reportData->closing_date)->startOfDay();
            $endDate = Carbon::parse($reportData->closing_date)->endOfDay();
        }

        // Use report's branch_id from database for fetching related data
        $filterBranchId = $reportBranchId;
        
        $this->writeLog('show', 'Fetching related data', [
            'filter_branch_id' => $filterBranchId,
            'start_date' => $startDate->toDateTimeString(),
            'end_date' => $endDate->toDateTimeString(),
        ]);
        
        if ($filterBranchId) {
            $ordersQuery = PosOrder::where('branch_id', $filterBranchId)
                ->with(['customer', 'waiter', 'table']);
            if ($reportData->start_date && $reportData->end_date) {
                $ordersQuery->whereBetween('created_at', [$startDate, $endDate]);
            } else {
                $ordersQuery->where('orders_date', Carbon::parse($reportData->closing_date)->format('Y-m-d'));
            }
            $orders = $ordersQuery->orderBy('created_at', 'desc')->get();
            $this->writeLog('show', 'Orders fetched', ['orders_count' => $orders->count()]);
        } else {
            $orders = collect([]);
            $this->writeLog('show', 'No branch_id, skipping orders fetch');
        }

        // Calculate payment type totals
        $paymentTypes = [
            'cash' => 0,
            'card' => 0,
            'online' => 0,
            'other' => 0,
        ];
        
        foreach ($orders as $order) {
            $paymentMode = strtolower($order->payment_mode ?? 'cash');
            if (isset($paymentTypes[$paymentMode])) {
                $paymentTypes[$paymentMode] += $order->grand_total;
            } else {
                $paymentTypes['other'] += $order->grand_total;
            }
        }

        // Fetch food bill orders
        $foodBillOrders = $orders->where('is_food_bill', true)->values();

        // Use the same branch_id for all queries (already fetched above)
        if ($filterBranchId) {
            // Fetch expenses within date range matching the report's branch_id
            $expenses = Expense::where('branch_id', $filterBranchId)
                ->whereBetween('expense_date', [$startDate->format('Y-m-d'), $endDate->format('Y-m-d')])
                ->with(['creator'])
                ->orderBy('expense_date', 'desc')
                ->get();

            // Fetch advance payments matching the report's branch_id
            $advancePayments = EmployeeWalletTransaction::where('branch_id', $filterBranchId)
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('payment_type', 'advance')
                ->where('transaction_type', 'credit')
                ->with(['employee', 'createdBy'])
                ->orderBy('created_at', 'desc')
                ->get();

            // Fetch daily wages matching the report's branch_id
            $dailyWages = EmployeeWalletTransaction::where('branch_id', $filterBranchId)
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('payment_type', 'daily_wage')
                ->where('transaction_type', 'debit')
                ->with(['employee', 'createdBy'])
                ->orderBy('created_at', 'desc')
                ->get();
        } else {
            $expenses = collect([]);
            $advancePayments = collect([]);
            $dailyWages = collect([]);
        }

        $responseData = [
            'report' => $reportData,
            'orders' => $orders,
            'orders_count' => $orders->count(),
            'payment_types' => $paymentTypes,
            'food_bill_orders' => $foodBillOrders,
            'food_bill_count' => $foodBillOrders->count(),
            'expenses' => $expenses,
            'expenses_count' => $expenses->count(),
            'advance_payments' => $advancePayments,
            'advance_payments_count' => $advancePayments->count(),
            'daily_wages' => $dailyWages,
            'daily_wages_count' => $dailyWages->count(),
        ];
        
        $this->writeLog('show', 'Response data prepared', [
            'orders_count' => $orders->count(),
            'expenses_count' => $expenses->count(),
            'advance_payments_count' => $advancePayments->count(),
            'daily_wages_count' => $dailyWages->count(),
            'report_has_data' => !empty($reportData),
            'report_keys' => $reportData ? array_keys($reportData->toArray()) : [],
        ]);
        
        return response()->json($responseData);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, $id)
    {
        $user = $request->user();
        
        // Get the report ID from route parameter
        $reportId = $request->route('id') ?? $id;
        
        $this->writeLog('update', 'Method called', [
            'user_id' => $user->id ?? null,
            'user_role' => $user->role ?? null,
            'route_id' => $reportId,
            'method_id' => $id,
            'request_data' => $request->all(),
        ]);
        
        // Find the report
        $dailyClosingReport = DailyClosingReport::find($reportId);
        
        if (!$dailyClosingReport) {
            $this->writeLog('update', 'Report not found', ['report_id' => $reportId]);
            return response()->json(['error' => 'Report not found'], 404);
        }
        
        $this->writeLog('update', 'Report found', [
            'report_id' => $dailyClosingReport->id,
            'report_branch_id' => $dailyClosingReport->branch_id,
            'report_restaurant_id' => $dailyClosingReport->restaurant_id,
        ]);

        // Access control - admin, restaurant_owner, and branch_manager can update
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            $this->writeLog('update', 'Unauthorized access', ['user_role' => $user->role ?? null]);
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Follow standard pattern to determine restaurant_id and branch_id
        $restaurantId = null;
        $branchId = null;

        if ($user->role === 'admin') {
            $restaurantId = $request->input('restaurant_id');
            $branchId = $request->input('branch_id');
            
            $this->writeLog('update', 'Admin role - getting from request', [
                'restaurant_id' => $restaurantId,
                'branch_id' => $branchId,
            ]);
            
            if (!$restaurantId || !$branchId) {
                $this->writeLog('update', 'Admin missing restaurant_id or branch_id', [
                    'restaurant_id' => $restaurantId,
                    'branch_id' => $branchId,
                ]);
                return response()->json(['error' => 'Restaurant and branch selection required for admin'], 400);
            }
        } elseif ($user->role === 'restaurant_owner') {
            $restaurantId = $user->restaurant_id;
            $branchId = $request->input('branch_id');
            
            $this->writeLog('update', 'Restaurant owner role', [
                'user_restaurant_id' => $restaurantId,
                'request_branch_id' => $branchId,
            ]);
            
            if (!$branchId) {
                $this->writeLog('update', 'Restaurant owner missing branch_id', ['branch_id' => $branchId]);
                return response()->json(['error' => 'Branch selection required'], 400);
            }
            
            if (!$restaurantId) {
                $this->writeLog('update', 'Restaurant owner not assigned to restaurant', ['user_restaurant_id' => $restaurantId]);
                return response()->json(['error' => 'Restaurant owner must be assigned to a restaurant'], 403);
            }
        } elseif ($user->role === 'branch_manager') {
            $restaurantId = $user->restaurant_id;
            $branchId = $user->branch_id;
            
            $this->writeLog('update', 'Branch manager role', [
                'user_restaurant_id' => $restaurantId,
                'user_branch_id' => $branchId,
            ]);
            
            if (!$branchId) {
                $this->writeLog('update', 'Branch manager not assigned to branch', ['user_branch_id' => $branchId]);
                return response()->json(['error' => 'Branch manager must be assigned to a branch'], 403);
            }
        }
        
        $this->writeLog('update', 'Determined restaurant_id and branch_id', [
            'restaurant_id' => $restaurantId,
            'branch_id' => $branchId,
        ]);

        // Fetch report's branch_id and restaurant_id from database
        $reportBranchId = \DB::table('daily_closing_reports')
            ->where('id', $dailyClosingReport->id)
            ->value('branch_id');
        
        $reportRestaurantId = \DB::table('daily_closing_reports')
            ->where('id', $dailyClosingReport->id)
            ->value('restaurant_id');
        
        // Fallback to model attributes if database query didn't return values
        if (!$reportBranchId) {
            $reportBranchId = $dailyClosingReport->branch_id;
        }
        if (!$reportRestaurantId) {
            $reportRestaurantId = $dailyClosingReport->restaurant_id;
        }

        // Verify access based on user role
        if ($user->role === 'admin') {
            // Admin: can update all reports (no additional check needed)
        } elseif ($user->role === 'restaurant_owner') {
            // Restaurant owner: can update reports for any branch under their restaurant
            if (!$reportRestaurantId || (int)$reportRestaurantId !== (int)$restaurantId) {
                return response()->json(['error' => 'You can only update reports for your restaurant branches'], 403);
            }
        } elseif ($user->role === 'branch_manager') {
            // Branch manager: can only update reports for their own branch
            if ($reportBranchId === null) {
                return response()->json(['error' => 'Report branch not found'], 403);
            }
            
            $userBranchId = (int)$branchId;
            $reportBranchIdInt = (int)$reportBranchId;
            
            if ($reportBranchIdInt !== $userBranchId) {
                return response()->json(['error' => 'You can only update reports for your branch'], 403);
            }
        } else {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Convert empty strings to null for time fields before validation
        $requestData = $request->all();
        $originalStartTime = $requestData['start_time'] ?? null;
        $originalEndTime = $requestData['end_time'] ?? null;
        
        if (isset($requestData['start_time']) && $requestData['start_time'] === '') {
            $requestData['start_time'] = null;
            $this->writeLog('update', 'Converted empty start_time to null', ['original' => $originalStartTime]);
        }
        if (isset($requestData['end_time']) && $requestData['end_time'] === '') {
            $requestData['end_time'] = null;
            $this->writeLog('update', 'Converted empty end_time to null', ['original' => $originalEndTime]);
        }
        $request->merge($requestData);
        
        $this->writeLog('update', 'After time field conversion', [
            'start_time' => $requestData['start_time'] ?? null,
            'end_time' => $requestData['end_time'] ?? null,
        ]);

        try {
            $validated = $request->validate([
                'start_date' => 'nullable|date',
                'start_time' => 'nullable|date_format:H:i',
                'end_date' => 'nullable|date',
                'end_time' => 'nullable|date_format:H:i',
                'available_cash' => 'sometimes|required|numeric|min:0',
                'gross_sales' => 'nullable|numeric|min:0',
                'online_card_payments' => 'nullable|numeric|min:0',
                'food_bills_total' => 'nullable|numeric|min:0',
                'expenses_paid' => 'nullable|numeric|min:0',
                'advance_payments' => 'nullable|numeric|min:0',
                'daily_wages' => 'nullable|numeric|min:0',
                'comments' => 'nullable|string|max:1000',
            ]);
            $this->writeLog('update', 'Validation passed', ['validated' => $validated]);
        } catch (\Illuminate\Validation\ValidationException $e) {
            $this->writeLog('update', 'Validation failed', [
                'errors' => $e->errors(),
                'request_data' => $request->all(),
            ]);
            throw $e;
        }

        // Validate date/time range if provided
        if (!empty($validated['start_date']) && !empty($validated['end_date'])) {
            $startDateTime = Carbon::parse($validated['start_date']);
            if (!empty($validated['start_time'])) {
                $startTime = Carbon::parse($validated['start_time']);
                $startDateTime->setTime($startTime->hour, $startTime->minute, $startTime->second);
            } else {
                $startDateTime->startOfDay();
            }
            
            $endDateTime = Carbon::parse($validated['end_date']);
            if (!empty($validated['end_time'])) {
                $endTime = Carbon::parse($validated['end_time']);
                $endDateTime->setTime($endTime->hour, $endTime->minute, $endTime->second);
                
                // Handle case where end_time is earlier in the day than start_time (crossing midnight)
                // Check if end date/time is actually before start date/time
                // If so, add 1 day to end_date to handle midnight crossing
                $tempEndDateTime = $endDateTime->copy();
                if ($tempEndDateTime->lte($startDateTime)) {
                    // End date/time is before or equal to start date/time, add 1 day
                    $endDateTime->addDay();
                    $this->writeLog('update', 'End date/time is before start date/time - adding 1 day to end date for midnight crossing', [
                        'start_date' => $startDateTime->format('Y-m-d H:i:s'),
                        'end_time' => $endTime->format('H:i'),
                        'original_end_date' => $validated['end_date'],
                        'adjusted_end_date' => $endDateTime->format('Y-m-d H:i:s'),
                    ]);
                }
            } else {
                $endDateTime->endOfDay();
            }
            
            // Final validation that start date/time is before end date/time
            if ($endDateTime->lte($startDateTime)) {
                $this->writeLog('update', 'End date/time must be after start date/time', [
                    'start_date' => $startDateTime->format('Y-m-d H:i:s'),
                    'end_date' => $endDateTime->format('Y-m-d H:i:s'),
                ]);
                return response()->json(['error' => 'End date/time must be after start date/time'], 422);
            }
            
            $this->writeLog('update', 'Date/time range validated', [
                'start_date' => $startDateTime->format('Y-m-d H:i:s'),
                'end_date' => $endDateTime->format('Y-m-d H:i:s'),
                'duration_hours' => $startDateTime->diffInHours($endDateTime),
            ]);
        }

        // Determine date/time range for recalculations if date/time changed
        $dateStart = null;
        $dateEnd = null;
        if (!empty($validated['start_date']) && !empty($validated['end_date'])) {
            $dateStart = $startDateTime;
            $dateEnd = $endDateTime;
        } else {
            // Use existing report's date/time range
            if ($dailyClosingReport->start_date && $dailyClosingReport->end_date) {
                $dateStart = Carbon::parse($dailyClosingReport->start_date);
                if ($dailyClosingReport->start_time) {
                    $startTime = Carbon::parse($dailyClosingReport->start_time);
                    $dateStart->setTime($startTime->hour, $startTime->minute, $startTime->second);
                } else {
                    $dateStart->startOfDay();
                }
                
                $dateEnd = Carbon::parse($dailyClosingReport->end_date);
                if ($dailyClosingReport->end_time) {
                    $endTime = Carbon::parse($dailyClosingReport->end_time);
                    $dateEnd->setTime($endTime->hour, $endTime->minute, $endTime->second);
                } else {
                    $dateEnd->endOfDay();
                }
            } else {
                $dateStart = Carbon::parse($dailyClosingReport->closing_date)->startOfDay();
                $dateEnd = Carbon::parse($dailyClosingReport->closing_date)->endOfDay();
            }
        }

        // Update calculated fields if provided, otherwise recalculate if date/time changed
        $dateTimeChanged = !empty($validated['start_date']) || !empty($validated['end_date']) || 
                          !empty($validated['start_time']) || !empty($validated['end_time']);
        $useOrdersDateRecalc = !($dailyClosingReport->start_date && $dailyClosingReport->end_date);
        $ordersDateStr = $dailyClosingReport->closing_date ? Carbon::parse($dailyClosingReport->closing_date)->format('Y-m-d') : null;

        $grossSales = isset($validated['gross_sales']) && $validated['gross_sales'] !== null
            ? $validated['gross_sales']
            : ($dateTimeChanged && $dateStart && $dateEnd
                ? round((function () use ($dailyClosingReport, $useOrdersDateRecalc, $ordersDateStr, $dateStart, $dateEnd) {
                    $q = PosOrder::where('branch_id', $dailyClosingReport->branch_id)
                        ->whereNull('deleted_at')
                        ->where('status', 'paid');
                    if ($useOrdersDateRecalc && $ordersDateStr) {
                        $q->where('orders_date', $ordersDateStr);
                    } else {
                        $q->whereBetween('created_at', [$dateStart->toDateTimeString(), $dateEnd->toDateTimeString()]);
                    }
                    return $q->sum('grand_total');
                })(), 2)
                : $dailyClosingReport->gross_sales);

        $onlineCardPayments = isset($validated['online_card_payments']) && $validated['online_card_payments'] !== null
            ? $validated['online_card_payments']
            : ($dateTimeChanged && $dateStart && $dateEnd
                ? round((function () use ($dailyClosingReport, $useOrdersDateRecalc, $ordersDateStr, $dateStart, $dateEnd) {
                    $q = PosOrder::where('branch_id', $dailyClosingReport->branch_id)
                        ->whereNull('deleted_at')
                        ->where('status', 'paid')
                        ->where('payment_mode', '!=', 'cash');
                    if ($useOrdersDateRecalc && $ordersDateStr) {
                        $q->where('orders_date', $ordersDateStr);
                    } else {
                        $q->whereBetween('created_at', [$dateStart->toDateTimeString(), $dateEnd->toDateTimeString()]);
                    }
                    return $q->sum('grand_total');
                })(), 2)
                : $dailyClosingReport->online_card_payments);

        $foodBillsTotal = isset($validated['food_bills_total']) && $validated['food_bills_total'] !== null
            ? $validated['food_bills_total']
            : ($dateTimeChanged && $dateStart && $dateEnd
                ? round((function () use ($dailyClosingReport, $useOrdersDateRecalc, $ordersDateStr, $dateStart, $dateEnd) {
                    $q = PosOrder::where('branch_id', $dailyClosingReport->branch_id)
                        ->whereNull('deleted_at')
                        ->where('status', 'paid')
                        ->where('is_food_bill', true);
                    if ($useOrdersDateRecalc && $ordersDateStr) {
                        $q->where('orders_date', $ordersDateStr);
                    } else {
                        $q->whereBetween('created_at', [$dateStart->toDateTimeString(), $dateEnd->toDateTimeString()]);
                    }
                    return $q->sum('grand_total');
                })(), 2)
                : $dailyClosingReport->food_bills_total);
        
        $expensesPaid = isset($validated['expenses_paid']) && $validated['expenses_paid'] !== null
            ? $validated['expenses_paid']
            : ($dateTimeChanged && $dateStart && $dateEnd
                ? round(Expense::where('branch_id', $dailyClosingReport->branch_id)
                    ->whereBetween('expense_date', [$dateStart->format('Y-m-d'), $dateEnd->format('Y-m-d')])
                    ->sum('amount'), 2)
                : $dailyClosingReport->expenses_paid);
        
        $advancePayments = isset($validated['advance_payments']) && $validated['advance_payments'] !== null
            ? $validated['advance_payments']
            : ($dateTimeChanged && $dateStart && $dateEnd
                ? round(EmployeeWalletTransaction::where('branch_id', $dailyClosingReport->branch_id)
                    ->whereBetween('created_at', [
                        $dateStart->toDateTimeString(),
                        $dateEnd->toDateTimeString()
                    ])
                    ->where('payment_type', 'advance')
                    ->where('transaction_type', 'credit')
                    ->sum('amount'), 2)
                : $dailyClosingReport->advance_payments);
        
        $dailyWages = isset($validated['daily_wages']) && $validated['daily_wages'] !== null
            ? $validated['daily_wages']
            : ($dateTimeChanged && $dateStart && $dateEnd
                ? round(EmployeeWalletTransaction::where('branch_id', $dailyClosingReport->branch_id)
                    ->whereBetween('created_at', [
                        $dateStart->toDateTimeString(),
                        $dateEnd->toDateTimeString()
                    ])
                    ->where('payment_type', 'daily_wage')
                    ->where('transaction_type', 'debit')
                    ->sum('amount'), 2)
                : $dailyClosingReport->daily_wages);

        // Recalculate totals
        $totalDeductions = $onlineCardPayments + $foodBillsTotal + $expensesPaid + $advancePayments + $dailyWages;
        $remainingCash = $grossSales - $totalDeductions;
        
        $availableCash = isset($validated['available_cash']) ? $validated['available_cash'] : $dailyClosingReport->available_cash;
        $difference = $remainingCash - $availableCash;
        $hasDifference = abs($difference) > 0.01;
        
        $this->writeLog('update', 'Difference calculation', [
            'gross_sales' => $grossSales,
            'online_card_payments' => $onlineCardPayments,
            'food_bills_total' => $foodBillsTotal,
            'expenses_paid' => $expensesPaid,
            'advance_payments' => $advancePayments,
            'daily_wages' => $dailyWages,
            'total_deductions' => $totalDeductions,
            'remaining_cash' => $remainingCash,
            'available_cash' => $availableCash,
            'difference' => $difference,
            'has_difference' => $hasDifference,
        ]);

        // Update the validated array with calculated values
        $validated['gross_sales'] = round($grossSales, 2);
        $validated['online_card_payments'] = round($onlineCardPayments, 2);
        $validated['food_bills_total'] = round($foodBillsTotal, 2);
        $validated['expenses_paid'] = round($expensesPaid, 2);
        $validated['advance_payments'] = round($advancePayments, 2);
        $validated['daily_wages'] = round($dailyWages, 2);
        $validated['total_deductions'] = round($totalDeductions, 2);
        $validated['remaining_cash'] = round($remainingCash, 2);
        $validated['difference'] = round($difference, 2);
        $validated['has_difference'] = $hasDifference;

        $validated['updated_by'] = $user->id;
        $dailyClosingReport->update($validated);

        $dailyClosingReport->load(['branch', 'restaurant', 'creator', 'updater']);

        return response()->json($dailyClosingReport);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy($id)
    {
        $user = request()->user();
        
        // Get the report ID from route parameter
        $reportId = request()->route('id') ?? $id;
        
        $this->writeLog('destroy', 'Method called', [
            'user_id' => $user->id ?? null,
            'user_role' => $user->role ?? null,
            'route_id' => $reportId,
            'method_id' => $id,
        ]);
        
        // Find the report
        $dailyClosingReport = DailyClosingReport::find($reportId);
        
        if (!$dailyClosingReport) {
            $this->writeLog('destroy', 'Report not found', ['report_id' => $reportId]);
            return response()->json(['error' => 'Report not found'], 404);
        }
        
        $this->writeLog('destroy', 'Report found', [
            'report_id' => $dailyClosingReport->id,
            'report_branch_id' => $dailyClosingReport->branch_id,
            'report_restaurant_id' => $dailyClosingReport->restaurant_id,
        ]);

        // Access control - admin, restaurant_owner, and branch_manager can delete
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            $this->writeLog('destroy', 'Unauthorized access', ['user_role' => $user->role ?? null]);
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Follow standard pattern to determine restaurant_id and branch_id
        $restaurantId = null;
        $branchId = null;

        if ($user->role === 'admin') {
            $restaurantId = request()->input('restaurant_id');
            $branchId = request()->input('branch_id');
            
            $this->writeLog('destroy', 'Admin role - getting from request', [
                'restaurant_id' => $restaurantId,
                'branch_id' => $branchId,
            ]);
            
            // Admin can delete any report, but we still fetch the report's branch_id for verification
        } elseif ($user->role === 'restaurant_owner') {
            $restaurantId = $user->restaurant_id;
            $branchId = request()->input('branch_id');
            
            $this->writeLog('destroy', 'Restaurant owner role', [
                'user_restaurant_id' => $restaurantId,
                'request_branch_id' => $branchId,
            ]);
            
            if (!$restaurantId) {
                $this->writeLog('destroy', 'Restaurant owner not assigned to restaurant', ['user_restaurant_id' => $restaurantId]);
                return response()->json(['error' => 'Restaurant owner must be assigned to a restaurant'], 403);
            }
        } elseif ($user->role === 'branch_manager') {
            $restaurantId = $user->restaurant_id;
            $branchId = $user->branch_id;
            
            $this->writeLog('destroy', 'Branch manager role', [
                'user_restaurant_id' => $restaurantId,
                'user_branch_id' => $branchId,
            ]);
            
            if (!$branchId) {
                $this->writeLog('destroy', 'Branch manager not assigned to branch', ['user_branch_id' => $branchId]);
                return response()->json(['error' => 'Branch manager must be assigned to a branch'], 403);
            }
        }
        
        $this->writeLog('destroy', 'Determined restaurant_id and branch_id', [
            'restaurant_id' => $restaurantId,
            'branch_id' => $branchId,
        ]);

        // Fetch branch_id directly from database table to ensure we have the correct value
        $reportBranchId = \DB::table('daily_closing_reports')
            ->where('id', $dailyClosingReport->id)
            ->value('branch_id');
        
        // Also get restaurant_id from database
        $reportRestaurantId = \DB::table('daily_closing_reports')
            ->where('id', $dailyClosingReport->id)
            ->value('restaurant_id');
        
        $this->writeLog('destroy', 'Fetched report IDs from database', [
            'report_id' => $dailyClosingReport->id,
            'db_branch_id' => $reportBranchId,
            'db_restaurant_id' => $reportRestaurantId,
            'model_branch_id' => $dailyClosingReport->branch_id,
            'model_restaurant_id' => $dailyClosingReport->restaurant_id,
        ]);
        
        // Fallback to model attributes if database query didn't return values
        if ($reportBranchId === null) {
            $reportBranchId = $dailyClosingReport->branch_id;
            $this->writeLog('destroy', 'Using model branch_id as fallback', ['branch_id' => $reportBranchId]);
        }
        if ($reportRestaurantId === null) {
            $reportRestaurantId = $dailyClosingReport->restaurant_id;
            $this->writeLog('destroy', 'Using model restaurant_id as fallback', ['restaurant_id' => $reportRestaurantId]);
        }

        // Verify access based on user role
        if ($user->role === 'admin') {
            // Admin: can delete all reports (no additional check needed)
            $this->writeLog('destroy', 'Admin access granted');
        } elseif ($user->role === 'restaurant_owner') {
            // Restaurant owner: can delete reports for any branch under their restaurant
            $this->writeLog('destroy', 'Checking restaurant owner access', [
                'report_restaurant_id' => $reportRestaurantId,
                'user_restaurant_id' => $restaurantId,
                'match' => ($reportRestaurantId !== null && (int)$reportRestaurantId === (int)$restaurantId),
            ]);
            
            if ($reportRestaurantId === null || (int)$reportRestaurantId !== (int)$restaurantId) {
                $this->writeLog('destroy', 'Restaurant owner access denied', [
                    'report_restaurant_id' => $reportRestaurantId,
                    'user_restaurant_id' => $restaurantId,
                ]);
                return response()->json(['error' => 'You can only delete reports for your restaurant branches'], 403);
            }
            $this->writeLog('destroy', 'Restaurant owner access granted');
        } elseif ($user->role === 'branch_manager') {
            // Branch manager: can only delete reports for their own branch
            $this->writeLog('destroy', 'Checking branch manager access', [
                'report_branch_id' => $reportBranchId,
                'user_branch_id' => $branchId,
            ]);
            
            if ($reportBranchId === null) {
                $this->writeLog('destroy', 'Report branch not found', ['report_branch_id' => $reportBranchId]);
                return response()->json(['error' => 'Report branch not found'], 403);
            }
            
            $userBranchId = (int)$branchId;
            $reportBranchIdInt = (int)$reportBranchId;
            
            $this->writeLog('destroy', 'Branch ID comparison', [
                'user_branch_id' => $userBranchId,
                'report_branch_id' => $reportBranchIdInt,
                'match' => ($reportBranchIdInt === $userBranchId),
            ]);
            
            if ($reportBranchIdInt !== $userBranchId) {
                $this->writeLog('destroy', 'Branch manager access denied', [
                    'user_branch_id' => $userBranchId,
                    'report_branch_id' => $reportBranchIdInt,
                ]);
                return response()->json(['error' => 'You can only delete reports for your branch'], 403);
            }
            $this->writeLog('destroy', 'Branch manager access granted');
        } else {
            $this->writeLog('destroy', 'Unauthorized role', ['user_role' => $user->role]);
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->writeLog('destroy', 'Deleting report', ['report_id' => $dailyClosingReport->id]);
        $dailyClosingReport->delete();
        $this->writeLog('destroy', 'Report deleted successfully', ['report_id' => $dailyClosingReport->id]);

        return response()->json(['message' => 'Daily closing report deleted successfully']);
    }

    /**
     * Export reports to Excel
     */
    public function export(Request $request)
    {
        $user = $request->user();

        // Access control
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $query = DailyClosingReport::with(['branch', 'restaurant', 'creator']);

        // Apply restaurant/branch filtering
        $this->applyRestaurantBranchFilter($query, $user, $request);

        // Date filters
        if ($request->has('date_from') && $request->date_from) {
            $query->whereDate('closing_date', '>=', $request->date_from);
        }

        if ($request->has('date_to') && $request->date_to) {
            $query->whereDate('closing_date', '<=', $request->date_to);
        }

        $reports = $query->orderBy('closing_date', 'desc')
            ->orderBy('created_at', 'desc')
            ->get();

        try {
            return \Maatwebsite\Excel\Facades\Excel::download(
                new \App\Exports\DailyClosingReportExport($reports),
                'daily_closing_reports_' . date('Y-m-d') . '.xlsx'
            );
        } catch (\Exception $e) {
            \Log::error('DailyClosingReport export error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            return response()->json(['error' => 'Failed to export reports: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Export single report details to Excel
     */
    public function exportDetails($id)
    {
        $user = request()->user();
        
        // Get the report ID from route parameter
        $reportId = request()->route('id') ?? $id;
        
        $this->writeLog('exportDetails', 'Method called', [
            'user_id' => $user->id ?? null,
            'user_role' => $user->role ?? null,
            'route_id' => $reportId,
            'method_id' => $id,
        ]);
        
        // Find the report
        $dailyClosingReport = DailyClosingReport::find($reportId);
        
        if (!$dailyClosingReport) {
            $this->writeLog('exportDetails', 'Report not found', ['report_id' => $reportId]);
            return response()->json(['error' => 'Report not found'], 404);
        }
        
        $this->writeLog('exportDetails', 'Report found', [
            'report_id' => $dailyClosingReport->id,
            'report_branch_id' => $dailyClosingReport->branch_id,
            'report_restaurant_id' => $dailyClosingReport->restaurant_id,
        ]);

        // Access control
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Refresh user to ensure we have latest data
        $user->refresh();
        
        // Load user's branch relationship for branch managers
        if ($user->isBranchManager() && !$user->relationLoaded('branch')) {
            $user->load('branch');
        }

        // Refresh report model to ensure we have latest data
        $dailyClosingReport->refresh();
        
        // Ensure report has branch relationship loaded
        if (!$dailyClosingReport->relationLoaded('branch')) {
            $dailyClosingReport->load('branch');
        }

        // Get user's context (restaurant_id and branch_id) from request headers/dropdowns or user relations
        $request = request();
        $userRestaurantId = null;
        $userBranchId = null;
        
        // For admins: get from request headers/dropdowns if available
        if ($user->isAdmin()) {
            $userRestaurantId = $request->header('X-Restaurant-Id') 
                ?? $request->input('restaurant_id')
                ?? session('restaurant_id')
                ?? null;
            $userBranchId = $request->header('X-Branch-Id')
                ?? $request->input('branch_id')
                ?? session('branch_id')
                ?? null;
        }
        // For restaurant owners: get from user or request
        elseif ($user->isRestaurantOwner()) {
            $userRestaurantId = $user->restaurant_id;
            $userBranchId = $request->header('X-Branch-Id')
                ?? $request->input('branch_id')
                ?? session('branch_id')
                ?? null;
        }
        // For branch managers: get from user's branch relationship
        elseif ($user->isBranchManager()) {
            if ($user->branch) {
                $userBranchId = $user->branch_id;
                $userRestaurantId = $user->branch->restaurant_id;
            } else {
                // Fallback to user's direct attributes
                $userBranchId = $user->branch_id;
                $userRestaurantId = $user->restaurant_id;
            }
        }

        // Get report's restaurant_id and branch_id (try multiple sources)
        $reportRestaurantId = $dailyClosingReport->restaurant_id 
            ?? ($dailyClosingReport->branch ? $dailyClosingReport->branch->restaurant_id : null);
        $reportBranchId = $dailyClosingReport->branch_id 
            ?? ($dailyClosingReport->branch ? $dailyClosingReport->branch->id : null);

        // Verify access based on user role
        if (!$user->isAdmin()) {
            // Restaurant owner: can view reports for any branch under their restaurant
            if ($user->isRestaurantOwner()) {
                if (!$userRestaurantId) {
                    return response()->json(['error' => 'Restaurant owner must be assigned to a restaurant'], 403);
                }
                
                // If report has restaurant_id, verify it matches user's restaurant
                if ($reportRestaurantId && (int)$reportRestaurantId !== (int)$userRestaurantId) {
                    return response()->json(['error' => 'You do not have access to this report'], 403);
                }
            }
            
            // Branch manager: can only view reports for their own branch
            if ($user->isBranchManager()) {
                if (!$userBranchId) {
                    return response()->json(['error' => 'Branch manager must be assigned to a branch'], 403);
                }
                
                // If report has branch_id, verify it matches user's branch
                if ($reportBranchId && (int)$reportBranchId !== (int)$userBranchId) {
                    return response()->json(['error' => 'You do not have access to this report'], 403);
                }
            }
        }

        // Get detailed data (same as show method)
        $dailyClosingReport->load(['branch', 'restaurant', 'creator', 'updater']);

        // Determine date/time range for fetching related data
        if ($dailyClosingReport->start_date && $dailyClosingReport->end_date) {
            $startDate = Carbon::parse($dailyClosingReport->start_date);
            if ($dailyClosingReport->start_time) {
                $startTime = Carbon::parse($dailyClosingReport->start_time);
                $startDate->setTime($startTime->hour, $startTime->minute, $startTime->second);
            } else {
                $startDate->startOfDay();
            }
            
            $endDate = Carbon::parse($dailyClosingReport->end_date);
            if ($dailyClosingReport->end_time) {
                $endTime = Carbon::parse($dailyClosingReport->end_time);
                $endDate->setTime($endTime->hour, $endTime->minute, $endTime->second);
            } else {
                $endDate->endOfDay();
            }
        } else {
            $startDate = Carbon::parse($dailyClosingReport->closing_date)->startOfDay();
            $endDate = Carbon::parse($dailyClosingReport->closing_date)->endOfDay();
        }

        $ordersQuery = PosOrder::where('branch_id', $dailyClosingReport->branch_id)
            ->with(['customer', 'waiter', 'table']);
        if ($dailyClosingReport->start_date && $dailyClosingReport->end_date) {
            $ordersQuery->whereBetween('created_at', [$startDate, $endDate]);
        } else {
            $ordersQuery->where('orders_date', Carbon::parse($dailyClosingReport->closing_date)->format('Y-m-d'));
        }
        $orders = $ordersQuery->orderBy('created_at', 'desc')->get();

        // Calculate payment type totals
        $paymentTypes = [
            'cash' => 0,
            'card' => 0,
            'online' => 0,
            'other' => 0,
        ];
        
        foreach ($orders as $order) {
            $paymentMode = strtolower($order->payment_mode ?? 'cash');
            if (isset($paymentTypes[$paymentMode])) {
                $paymentTypes[$paymentMode] += $order->grand_total;
            } else {
                $paymentTypes['other'] += $order->grand_total;
            }
        }

        $foodBillOrders = $orders->where('is_food_bill', true)->values();

        // Fetch expenses
        $filterBranchId = $reportBranchId ?? $userBranchId;
        if ($filterBranchId) {
            $expenses = Expense::where('branch_id', $filterBranchId)
                ->whereBetween('expense_date', [$startDate->format('Y-m-d'), $endDate->format('Y-m-d')])
                ->with(['creator'])
                ->orderBy('expense_date', 'desc')
                ->get();
        } else {
            $expenses = collect([]);
        }

        // Fetch advance payments
        $filterBranchId = $reportBranchId ?? $userBranchId;
        if ($filterBranchId) {
            $advancePayments = EmployeeWalletTransaction::where('branch_id', $filterBranchId)
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('payment_type', 'advance')
                ->where('transaction_type', 'credit')
                ->with(['employee', 'createdBy'])
                ->orderBy('created_at', 'desc')
                ->get();

            // Fetch daily wages
            $dailyWages = EmployeeWalletTransaction::where('branch_id', $filterBranchId)
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('payment_type', 'daily_wage')
                ->where('transaction_type', 'debit')
                ->with(['employee', 'createdBy'])
                ->orderBy('created_at', 'desc')
                ->get();
        } else {
            $advancePayments = collect([]);
            $dailyWages = collect([]);
        }

        $reportData = [
            'report' => $dailyClosingReport,
            'orders' => $orders,
            'orders_count' => $orders->count(),
            'payment_types' => $paymentTypes,
            'food_bill_orders' => $foodBillOrders,
            'food_bill_count' => $foodBillOrders->count(),
            'expenses' => $expenses,
            'expenses_count' => $expenses->count(),
            'advance_payments' => $advancePayments,
            'advance_payments_count' => $advancePayments->count(),
            'daily_wages' => $dailyWages,
            'daily_wages_count' => $dailyWages->count(),
        ];

        try {
            // Format date string safely
            $dateStr = $dailyClosingReport->closing_date 
                ? Carbon::parse($dailyClosingReport->closing_date)->format('Y-m-d')
                : date('Y-m-d');
            
            $this->writeLog('exportDetails', 'Starting export', [
                'report_id' => $dailyClosingReport->id,
                'date_str' => $dateStr,
            ]);
            
            return \Maatwebsite\Excel\Facades\Excel::download(
                new \App\Exports\DailyClosingReportDetailsExport($reportData),
                "daily_closing_report_{$dateStr}.xlsx"
            );
        } catch (\Exception $e) {
            $this->writeLog('exportDetails', 'Export error', [
                'report_id' => $dailyClosingReport->id ?? null,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            \Log::error('DailyClosingReport details export error', [
                'report_id' => $dailyClosingReport->id ?? null,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            return response()->json(['error' => 'Failed to export report details: ' . $e->getMessage()], 500);
        }
    }
}
