<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\CaseRecord;
use App\Models\CaseSuspect;
use App\Models\BailApplication;
use App\Models\BailCondition;
use App\Traits\StationDataFilter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class BailApplicationController extends Controller
{
    use StationDataFilter;

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        // Start with station-filtered bail applications
        $query = $this->getFilteredBailApplications()
            ->with(['suspect', 'case', 'approvedBy'])
            ->orderBy('created_at', 'desc');
            
        // Apply filters if provided
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }
        
        if ($request->filled('case_id')) {
            $query->where('case_id', $request->case_id);
        }
        
        if ($request->filled('suspect_id')) {
            $query->where('suspect_id', $request->suspect_id);
        }
        
        if ($request->filled('application_date_from')) {
            $query->whereDate('application_date', '>=', $request->application_date_from);
        }
        
        if ($request->filled('application_date_to')) {
            $query->whereDate('application_date', '<=', $request->application_date_to);
        }
        
        $applications = $query->paginate(10);
        
        // Get data for filters - station filtered
        $cases = $this->getFilteredCases()->orderBy('case_number')->get();
        $suspects = CaseSuspect::whereIn('case_id', $cases->pluck('id'))->orderBy('full_name')->get();
        
        return view('bail.index', compact('applications', 'cases', 'suspects'));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create(Request $request)
    {
        $cases = $this->getFilteredCases()->orderBy('case_number')->get();
        $suspects = collect();
        $selectedCase = null;
        
        // If case_id is provided, load suspects related to that case
        if ($request->filled('case_id')) {
            $selectedCase = $this->getFilteredCases()->findOrFail($request->case_id);
            $suspects = CaseSuspect::where('case_id', $selectedCase->id)->get();
        }
        
        $officers = $this->getFilteredOfficers()->orderBy('name')->get();
        $conditionTypes = BailCondition::getConditionTypes();
        
        // Generate a unique application number
        $year = now()->format('Y');
        $lastApplication = BailApplication::where('application_number', 'like', "BAIL-{$year}-%")
            ->orderBy('application_number', 'desc')
            ->first();
            
        $nextNumber = 1;
        if ($lastApplication) {
            $parts = explode('-', $lastApplication->application_number);
            $nextNumber = intval(end($parts)) + 1;
        }
        
        $applicationNumber = sprintf("BAIL-%s-%03d", $year, $nextNumber);
        
        return view('bail.create', compact(
            'cases', 
            'suspects', 
            'officers', 
            'conditionTypes', 
            'applicationNumber',
            'selectedCase'
        ));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        // Validate the request
        $validated = $request->validate([
            'case_id' => 'required|exists:cases,id',
            'suspect_id' => 'required|exists:suspects,id',
            'application_number' => 'required|string|unique:bail_applications,application_number',
            'application_date' => 'required|date',
            'status' => 'required|in:pending,approved,rejected,revoked',
            'approval_date' => 'nullable|date|required_if:status,approved',
            'expiry_date' => 'nullable|date|after_or_equal:approval_date',
            'amount' => 'nullable|numeric|min:0',
            'surety_name' => 'nullable|string|max:255',
            'surety_contact' => 'nullable|string|max:255',
            'surety_address' => 'nullable|string|max:255',
            'surety_relationship' => 'nullable|string|max:255',
            'surety_id_type' => 'nullable|string|max:255',
            'surety_id_number' => 'nullable|string|max:255',
            'reason' => 'nullable|string',
            'notes' => 'nullable|string',
            'approved_by' => 'nullable|exists:users,id|required_if:status,approved',
            'condition_type.*' => 'nullable|string',
            'condition_description.*' => 'nullable|string|required_with:condition_type.*',
        ]);
        
        // Start a database transaction
        DB::beginTransaction();
        
        try {
            // Create the bail application
            $application = new BailApplication($validated);
            $application->created_by = Auth::id();
            $application->updated_by = Auth::id();
            $application->save();
            
            // Create bail conditions if provided
            if ($request->has('condition_type')) {
                foreach ($request->condition_type as $key => $type) {
                    if (!empty($type) && !empty($request->condition_description[$key])) {
                        $condition = new BailCondition([
                            'bail_application_id' => $application->id,
                            'condition_type' => $type,
                            'description' => $request->condition_description[$key],
                            'created_by' => Auth::id(),
                            'updated_by' => Auth::id(),
                        ]);
                        $condition->save();
                    }
                }
            }
            
            DB::commit();
            
            return redirect()->route('bail.show', $application->id)
                ->with('success', 'Bail application created successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()->withErrors(['error' => 'Failed to create bail application: ' . $e->getMessage()]);
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $application = $this->getFilteredBailApplications()
            ->with(['suspect', 'case', 'approvedBy', 'conditions'])
            ->findOrFail($id);
            
        // Check if user can access this bail application's case station
        if (!Auth::user()->canAccessStationData($application->case->station_id)) {
            return redirect()->route('bail.index')
                ->with('error', 'You do not have permission to view this bail application.');
        }
        
        $officers = $this->getFilteredOfficers()->orderBy('name')->get();
        
        return view('bail.show', compact('application', 'officers'));
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {
        $application = $this->getFilteredBailApplications()->findOrFail($id);
        
        // Check if user can access this bail application's case station
        if (!Auth::user()->canAccessStationData($application->case->station_id)) {
            return redirect()->route('bail.index')
                ->with('error', 'You do not have permission to edit this bail application.');
        }
        
        $cases = $this->getFilteredCases()->orderBy('case_number')->get();
        $suspects = CaseSuspect::where('case_id', $application->case_id)->get();
        $officers = $this->getFilteredOfficers()->orderBy('name')->get();
        $conditionTypes = BailCondition::getConditionTypes();
        
        return view('bail.edit', compact('application', 'cases', 'suspects', 'officers', 'conditionTypes'));
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, string $id)
    {
        $application = $this->getFilteredBailApplications()->findOrFail($id);
        
        // Validate the request
        $validated = $request->validate([
            'case_id' => 'required|exists:cases,id',
            'suspect_id' => 'required|exists:suspects,id',
            'application_number' => 'required|string|unique:bail_applications,application_number,' . $id,
            'application_date' => 'required|date',
            'status' => 'required|in:pending,approved,rejected,revoked',
            'approval_date' => 'nullable|date|required_if:status,approved',
            'expiry_date' => 'nullable|date|after_or_equal:approval_date',
            'amount' => 'nullable|numeric|min:0',
            'surety_name' => 'nullable|string|max:255',
            'surety_contact' => 'nullable|string|max:255',
            'surety_address' => 'nullable|string|max:255',
            'surety_relationship' => 'nullable|string|max:255',
            'surety_id_type' => 'nullable|string|max:255',
            'surety_id_number' => 'nullable|string|max:255',
            'reason' => 'nullable|string',
            'notes' => 'nullable|string',
            'approved_by' => 'nullable|exists:users,id|required_if:status,approved',
            'existing_condition_id.*' => 'nullable|exists:bail_conditions,id',
            'existing_condition_type.*' => 'nullable|string',
            'existing_condition_description.*' => 'nullable|string',
            'existing_condition_is_fulfilled.*' => 'nullable|boolean',
            'existing_condition_fulfillment_date.*' => 'nullable|date',
            'existing_condition_fulfillment_notes.*' => 'nullable|string',
            'existing_condition_verified_by.*' => 'nullable|exists:users,id',
            'condition_type.*' => 'nullable|string',
            'condition_description.*' => 'nullable|string|required_with:condition_type.*',
        ]);
        
        // Start a database transaction
        DB::beginTransaction();
        
        try {
            // Update the bail application
            $application->fill($validated);
            $application->updated_by = Auth::id();
            $application->save();
            
            // Update existing conditions
            if ($request->has('existing_condition_id')) {
                foreach ($request->existing_condition_id as $key => $conditionId) {
                    $condition = BailCondition::find($conditionId);
                    if ($condition) {
                        $condition->condition_type = $request->existing_condition_type[$key];
                        $condition->description = $request->existing_condition_description[$key];
                        $condition->is_fulfilled = $request->has('existing_condition_is_fulfilled') && 
                                                  isset($request->existing_condition_is_fulfilled[$key]);
                        
                        if ($condition->is_fulfilled) {
                            $condition->fulfillment_date = $request->existing_condition_fulfillment_date[$key] ?? now();
                            $condition->fulfillment_notes = $request->existing_condition_fulfillment_notes[$key];
                            $condition->verified_by = $request->existing_condition_verified_by[$key] ?? Auth::id();
                        }
                        
                        $condition->updated_by = Auth::id();
                        $condition->save();
                    }
                }
            }
            
            // Create new conditions if provided
            if ($request->has('condition_type')) {
                foreach ($request->condition_type as $key => $type) {
                    if (!empty($type) && !empty($request->condition_description[$key])) {
                        $condition = new BailCondition([
                            'bail_application_id' => $application->id,
                            'condition_type' => $type,
                            'description' => $request->condition_description[$key],
                            'created_by' => Auth::id(),
                            'updated_by' => Auth::id(),
                        ]);
                        $condition->save();
                    }
                }
            }
            
            DB::commit();
            
            return redirect()->route('bail.show', $application->id)
                ->with('success', 'Bail application updated successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()->withErrors(['error' => 'Failed to update bail application: ' . $e->getMessage()]);
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {
        $application = $this->getFilteredBailApplications()->findOrFail($id);
        
        try {
            $application->delete();
            return redirect()->route('bail.index')
                ->with('success', 'Bail application deleted successfully.');
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to delete bail application: ' . $e->getMessage()]);
        }
    }
    
    /**
     * Get suspects for a specific case via AJAX.
     */
    public function getSuspects(Request $request)
    {
        if (!$request->case_id) {
            return response()->json([]);
        }
        
        // Check if user can access this case
        $case = $this->getFilteredCases()->find($request->case_id);
        if (!$case) {
            return response()->json([]);
        }
        
        $suspects = CaseSuspect::where('case_id', $request->case_id)
            ->select('id', 'full_name', 'alias')
            ->get()
            ->map(function($suspect) {
                return [
                    'id' => $suspect->id,
                    'name' => $suspect->full_name . ($suspect->alias ? ' (' . $suspect->alias . ')' : '')
                ];
            });
            
        return response()->json($suspects);
    }
    
    /**
     * Update the status of a bail application.
     */
    public function updateStatus(Request $request, string $id)
    {
        $application = $this->getFilteredBailApplications()->findOrFail($id);
        
        // Check if user can access this bail application's case station
        if (!Auth::user()->canAccessStationData($application->case->station_id)) {
            return redirect()->route('bail.index')
                ->with('error', 'You do not have permission to update this bail application.');
        }
        
        $validated = $request->validate([
            'status' => 'required|in:pending,approved,rejected,revoked',
            'notes' => 'nullable|string',
            'approval_date' => 'nullable|date|required_if:status,approved',
            'expiry_date' => 'nullable|date|after_or_equal:approval_date',
            'approved_by' => 'nullable|exists:users,id|required_if:status,approved',
        ]);
        
        try {
            $application->status = $validated['status'];
            $application->notes = $request->filled('notes') 
                ? ($application->notes . "\n" . now()->format('Y-m-d H:i') . ": {$validated['notes']}")
                : $application->notes;
                
            if ($validated['status'] === 'approved') {
                $application->approval_date = $validated['approval_date'];
                $application->expiry_date = $validated['expiry_date'];
                $application->approved_by = $validated['approved_by'];
            }
            
            $application->updated_by = Auth::id();
            $application->save();
            
            return redirect()->route('bail.show', $application->id)
                ->with('success', 'Bail application status updated successfully.');
        } catch (\Exception $e) {
            return back()->withInput()->withErrors(['error' => 'Failed to update status: ' . $e->getMessage()]);
        }
    }
    
    /**
     * Mark a bail condition as fulfilled or unfulfilled.
     */
    public function updateCondition(Request $request, string $id)
    {
        $condition = BailCondition::findOrFail($id);
        
        $validated = $request->validate([
            'is_fulfilled' => 'required|boolean',
            'fulfillment_date' => 'nullable|date|required_if:is_fulfilled,1',
            'fulfillment_notes' => 'nullable|string',
            'verified_by' => 'nullable|exists:users,id|required_if:is_fulfilled,1',
        ]);
        
        try {
            $condition->is_fulfilled = $validated['is_fulfilled'];
            
            if ($validated['is_fulfilled']) {
                $condition->fulfillment_date = $validated['fulfillment_date'];
                $condition->fulfillment_notes = $validated['fulfillment_notes'];
                $condition->verified_by = $validated['verified_by'];
            } else {
                $condition->fulfillment_date = null;
                $condition->fulfillment_notes = null;
                $condition->verified_by = null;
            }
            
            $condition->updated_by = Auth::id();
            $condition->save();
            
            return redirect()->route('bail.show', $condition->bail_application_id)
                ->with('success', 'Bail condition updated successfully.');
        } catch (\Exception $e) {
            return back()->withInput()->withErrors(['error' => 'Failed to update condition: ' . $e->getMessage()]);
        }
    }
}
