<?php

namespace App\Http\Controllers\Mentorship;

use App\Http\Controllers\Controller;
use App\Models\Mentorship\Assignment;
use App\Models\Mentorship\Programme;
use App\Models\Mentorship\Application;
use App\Models\User;
use App\Services\Mentorship\AssignmentService;
use App\Http\Requests\Mentorship\AssignmentRequest;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;

class AssignmentController extends Controller
{
    protected AssignmentService $assignmentService;

    public function __construct(AssignmentService $assignmentService)
    {
        $this->assignmentService = $assignmentService;
    }

    /**
     * Display a listing of assignments.
     */
    public function index(Request $request)
    {
        abort_unless(auth()->user()->can('view mentorship assignments'), 403);

        $user = auth()->user();

        $filters = [
            'status' => $request->get('status'),
            'programme_id' => $request->get('programme_id'),
            'mentor_id' => $request->get('mentor_id'),
            'mentee_id' => $request->get('mentee_id'),
            'search' => $request->get('search'),
            'sort_by' => $request->get('sort_by', 'created_at'),
            'sort_order' => $request->get('sort_order', 'desc'),
        ];

        // Mentors and Mentees only see their own assignments
        $isOwnOnly = $user->hasRole('Mentor') || $user->hasRole('Mentee');
        if ($isOwnOnly) {
            $filters['user_id'] = $user->id;
        }

        $assignments = $this->assignmentService->getAssignments($filters);

        $programmes = Programme::active()->orderBy('title')->get();

        return view('mentorship.assignments.index', compact('assignments', 'programmes', 'filters', 'isOwnOnly'));
    }

    /**
     * Show the form for creating a new assignment.
     */
    public function create(Request $request)
    {
        abort_unless(auth()->user()->can('create mentorship assignments'), 403);

        $programmeId = $request->get('programme_id');
        $programme = $programmeId ? Programme::find($programmeId) : null;

        // Get approved mentors
        $mentors = User::role('Mentor')
            ->whereHas('mentorApplications', function ($q) use ($programmeId) {
                $q->where('status', 'approved');
                if ($programmeId) {
                    $q->where('programme_id', $programmeId);
                }
            })
            ->orderBy('name')
            ->get();

        // Get unassigned mentees
        $mentees = User::role('Mentee')
            ->whereHas('menteeApplications', function ($q) use ($programmeId) {
                $q->where('status', 'approved');
                if ($programmeId) {
                    $q->where('programme_id', $programmeId);
                }
            })
            ->whereDoesntHave('menteeAssignments', function ($q) use ($programmeId) {
                $q->whereIn('status', ['pending_acceptance', 'active']);
                if ($programmeId) {
                    $q->where('programme_id', $programmeId);
                }
            })
            ->orderBy('name')
            ->get();

        $programmes = Programme::active()->orderBy('title')->get();

        return view('mentorship.assignments.create', compact('programmes', 'programme', 'mentors', 'mentees'));
    }

    /**
     * Store a newly created assignment.
     */
    public function store(AssignmentRequest $request)
    {
        abort_unless(auth()->user()->can('create mentorship assignments'), 403);

        try {
            $assignment = $this->assignmentService->create($request->validated());

            return redirect()
                ->route('mentorship.assignments.show', $assignment)
                ->with('success', 'Assignment created successfully.');
        } catch (\Exception $e) {
            return back()
                ->withInput()
                ->withErrors(['error' => $e->getMessage()]);
        }
    }

    /**
     * Display the specified assignment.
     */
    public function show(Assignment $assignment)
    {
        abort_unless(auth()->user()->can('view mentorship assignments'), 403);

        $user = auth()->user();

        // Mentors and Mentees can only view their own assignments
        if ($user->hasRole('Mentor') || $user->hasRole('Mentee')) {
            abort_unless(
                $assignment->mentor_id === $user->id || $assignment->mentee_id === $user->id,
                403
            );
        }

        $assignment->load([
            'programme',
            'mentor',
            'mentee',
            'mentorApplication',
            'menteeApplication',
            'assigner',
            'sessions' => fn($q) => $q->latest()->limit(10),
            'certificate',
        ]);

        return view('mentorship.assignments.show', compact('assignment'));
    }

    /**
     * Show the form for editing the specified assignment.
     */
    public function edit(Assignment $assignment)
    {
        abort_unless(auth()->user()->can('edit mentorship assignments'), 403);

        $assignment->load(['programme', 'mentor', 'mentee']);

        return view('mentorship.assignments.edit', compact('assignment'));
    }

    /**
     * Update the specified assignment.
     */
    public function update(Request $request, Assignment $assignment)
    {
        abort_unless(auth()->user()->can('edit mentorship assignments'), 403);

        $request->validate([
            'goals' => 'nullable|string|max:3000',
            'notes' => 'nullable|string|max:2000',
            'start_date' => 'nullable|date',
            'end_date' => 'nullable|date|after:start_date',
            'meeting_frequency' => 'nullable|in:daily,weekly,biweekly,monthly',
            'milestones' => 'nullable|array',
        ]);

        $assignment->update($request->only([
            'goals', 'notes', 'start_date', 'end_date', 'meeting_frequency', 'milestones'
        ]));

        return redirect()
            ->route('mentorship.assignments.show', $assignment)
            ->with('success', 'Assignment updated successfully.');
    }

    /**
     * Accept an assignment.
     */
    public function accept(Assignment $assignment): JsonResponse
    {
        $user = auth()->user();
        
        // Determine if user is mentor or mentee
        $role = null;
        if ($assignment->mentor_id === $user->id) {
            $role = 'mentor';
        } elseif ($assignment->mentee_id === $user->id) {
            $role = 'mentee';
        }

        if (!$role) {
            return response()->json([
                'success' => false,
                'message' => 'You are not part of this assignment.',
            ], 403);
        }

        try {
            $this->assignmentService->accept($assignment, $user, $role);

            return response()->json([
                'success' => true,
                'message' => 'Assignment accepted successfully.',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 422);
        }
    }

    /**
     * Complete an assignment.
     */
    public function complete(Request $request, Assignment $assignment)
    {
        abort_unless(auth()->user()->can('complete mentorship assignments'), 403);

        $request->validate([
            'completion_notes' => 'nullable|string|max:2000',
        ]);

        try {
            $this->assignmentService->complete($assignment, $request->validated());

            return redirect()
                ->route('mentorship.assignments.show', $assignment)
                ->with('success', 'Assignment marked as completed.');
        } catch (\Exception $e) {
            return back()->withErrors(['error' => $e->getMessage()]);
        }
    }

    /**
     * Cancel an assignment.
     */
    public function cancel(Request $request, Assignment $assignment)
    {
        abort_unless(auth()->user()->can('cancel mentorship assignments'), 403);

        $request->validate([
            'reason' => 'required|string|max:1000',
        ]);

        try {
            $this->assignmentService->cancel($assignment, $request->reason);

            return redirect()
                ->route('mentorship.assignments.show', $assignment)
                ->with('success', 'Assignment cancelled.');
        } catch (\Exception $e) {
            return back()->withErrors(['error' => $e->getMessage()]);
        }
    }

    /**
     * Reassign mentee to different mentor.
     */
    public function reassign(Request $request, Assignment $assignment)
    {
        abort_unless(auth()->user()->can('reassign mentorship assignments'), 403);

        $request->validate([
            'new_mentor_id' => 'required|exists:users,id',
            'reason' => 'required|string|max:1000',
        ]);

        try {
            $newAssignment = $this->assignmentService->reassign(
                $assignment,
                $request->new_mentor_id,
                $request->reason
            );

            return redirect()
                ->route('mentorship.assignments.show', $newAssignment)
                ->with('success', 'Mentee reassigned successfully.');
        } catch (\Exception $e) {
            return back()->withErrors(['error' => $e->getMessage()]);
        }
    }

    /**
     * Auto-match mentees with mentors.
     */
    public function autoMatch(Request $request, Programme $programme): JsonResponse
    {
        abort_unless(auth()->user()->can('create mentorship assignments'), 403);

        try {
            $result = $this->assignmentService->autoMatch($programme, $request->get('options', []));

            return response()->json([
                'success' => true,
                'matched' => count($result['matched']),
                'unmatched' => count($result['unmatched']),
                'message' => "Matched {$result['matched']->count()} pairs.",
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 422);
        }
    }

    /**
     * Get available mentors for a programme (AJAX).
     */
    public function getAvailableMentors(Programme $programme): JsonResponse
    {
        $mentors = User::role('Mentor')
            ->whereHas('mentorApplications', function ($q) use ($programme) {
                $q->where('programme_id', $programme->id)
                    ->where('status', 'approved');
            })
            ->withCount(['mentorAssignments as active_assignments' => function ($q) use ($programme) {
                $q->where('programme_id', $programme->id)
                    ->whereIn('status', ['pending_acceptance', 'active']);
            }])
            ->having('active_assignments', '<', $programme->max_mentees ?: 999)
            ->get();

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

    /**
     * Get unassigned mentees for a programme (AJAX).
     */
    public function getUnassignedMentees(Programme $programme): JsonResponse
    {
        $mentees = User::role('Mentee')
            ->whereHas('menteeApplications', function ($q) use ($programme) {
                $q->where('programme_id', $programme->id)
                    ->where('status', 'approved');
            })
            ->whereDoesntHave('menteeAssignments', function ($q) use ($programme) {
                $q->where('programme_id', $programme->id)
                    ->whereIn('status', ['pending_acceptance', 'active']);
            })
            ->get();

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