<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Complaint;
use App\Models\User;
use App\Notifications\ComplaintFiledAgainstYouNotification;
use App\Notifications\ComplaintStatusChangedNotification;
use App\Notifications\ComplaintSubmittedNotification;
use App\Services\HrmsNotificationService;
use App\Support\FormTextRules;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;

class ComplaintController extends Controller
{
    public function __construct(
        protected HrmsNotificationService $notifier
    ) {}

    public function index(Request $request)
    {
        $user = Auth::user();
        $canManage = $this->canManageAllComplaints($user);

        if (! $canManage) {
            return redirect()->to(route('my-hr-records.index') . '#complaints');
        }

        $query = Complaint::with(['fromUser', 'againstUser']);
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }
        $complaints = $query->orderByDesc('complaint_date')->paginate(15)->withQueryString();

        $kpis = $this->buildKpis($user, $canManage);

        return view('hr.complaints', compact('complaints', 'canManage', 'kpis'));
    }

    public function create()
    {
        $user = Auth::user();
        $canManage = $this->canManageAllComplaints($user);

        if (! $canManage) {
            return redirect()->to(route('my-hr-records.index') . '#complaints');
        }

        $users = $this->companyUsersQuery()->orderBy('name')->get();

        return view('hr.complaints-create', compact('users', 'canManage'));
    }

    public function store(Request $request)
    {
        $user = Auth::user();
        $canManage = $this->canManageAllComplaints($user);
        $companyId = $user->company_id;
        if (! $companyId) {
            abort(403, 'Company not found.');
        }

        $rules = [
            'against_user_id' => [
                'nullable',
                Rule::exists('users', 'id')->where(fn ($q) => $q->where('company_id', $companyId)),
            ],
            'subject' => FormTextRules::notNumericOnly(true, 191),
            'description' => 'nullable|string|max:2000',
            'complaint_date' => 'required|date',
            'status' => 'nullable|in:pending,under_review,resolved,rejected',
        ];

        if ($canManage) {
            $rules['from_user_id'] = [
                'required',
                Rule::exists('users', 'id')->where(fn ($q) => $q->where('company_id', $companyId)),
            ];
        }

        $validated = $request->validate($rules, FormTextRules::messages());

        if (! $canManage) {
            $validated['from_user_id'] = $user->id;
            $validated['status'] = 'pending';
        } else {
            $validated['status'] = $validated['status'] ?? 'pending';
        }

        $validated['company_id'] = $companyId;
        $complaint = Complaint::create($validated);
        $complaint->load(['fromUser', 'againstUser']);

        if ($companyId) {
            $excludeIds = [(int) $user->id];
            if (! empty($validated['against_user_id'])) {
                $excludeIds[] = (int) $validated['against_user_id'];
            }
            $this->notifier->notifyUsersWithAnyPermission(
                (int) $companyId,
                ['hr_operations_view'],
                new ComplaintSubmittedNotification($complaint),
                $excludeIds
            );
        }

        $againstId = (int) ($complaint->against_user_id ?? 0);
        if ($againstId > 0 && $againstId !== (int) $user->id) {
            $complaint->againstUser?->notify(new ComplaintFiledAgainstYouNotification($complaint));
        }

        if (! $canManage) {
            return redirect()->to(route('my-hr-records.index') . '#complaints')
                ->with('success', 'Complaint recorded successfully.');
        }

        return redirect()->route('complaints.index')->with('success', 'Complaint recorded successfully.');
    }

    public function edit(Complaint $complaint)
    {
        $this->authorizeComplaint($complaint);
        $users = $this->companyUsersQuery()->orderBy('name')->get();

        return view('hr.complaints-edit', compact('complaint', 'users'));
    }

    public function update(Request $request, Complaint $complaint)
    {
        $this->authorizeComplaint($complaint);
        $companyId = Auth::user()?->company_id;
        $validated = $request->validate([
            'from_user_id' => [
                'required',
                Rule::exists('users', 'id')->where(fn ($q) => $q->where('company_id', $companyId)),
            ],
            'against_user_id' => [
                'nullable',
                Rule::exists('users', 'id')->where(fn ($q) => $q->where('company_id', $companyId)),
            ],
            'subject' => FormTextRules::notNumericOnly(true, 191),
            'description' => 'nullable|string|max:2000',
            'complaint_date' => 'required|date',
            'status' => 'required|in:pending,under_review,resolved,rejected',
            'resolution_notes' => 'nullable|string|max:2000',
        ], FormTextRules::messages());

        if ($validated['status'] === 'resolved' && empty(trim((string) ($validated['resolution_notes'] ?? '')))) {
            return back()->withInput()->withErrors([
                'resolution_notes' => 'Resolution notes are required when marking as resolved.',
            ]);
        }

        $previousStatus = $complaint->status;

        $complaint->update($validated);

        if ($previousStatus !== $complaint->status && $complaint->fromUser) {
            $complaint->fromUser->notify(new ComplaintStatusChangedNotification($complaint, $complaint->status));
        }

        return redirect()->route('complaints.index')->with('success', 'Complaint updated successfully.');
    }

    public function destroy(Complaint $complaint)
    {
        $this->authorizeComplaint($complaint);
        $complaint->delete();

        return redirect()->route('complaints.index')->with('success', 'Complaint deleted successfully.');
    }

    /**
     * @return array<string, int>
     */
    protected function buildKpis(?User $user, bool $canManage): array
    {
        if (! $user) {
            return [];
        }

        if ($canManage) {
            $base = Complaint::query();

            return [
                'total' => (clone $base)->count(),
                'pending' => (clone $base)->where('status', 'pending')->count(),
                'under_review' => (clone $base)->where('status', 'under_review')->count(),
                'resolved' => (clone $base)->where('status', 'resolved')->count(),
                'against_me' => (clone $base)->where('against_user_id', $user->id)->count(),
            ];
        }

        return [
            'against_me' => Complaint::query()->where('against_user_id', $user->id)->count(),
            'raised' => Complaint::query()->where('from_user_id', $user->id)->count(),
            'raised_pending' => Complaint::query()
                ->where('from_user_id', $user->id)
                ->where('status', 'pending')
                ->count(),
        ];
    }

    protected function canManageAllComplaints(?User $user): bool
    {
        if (! $user) {
            return false;
        }

        if ($user->isCompanyAccountAdmin()) {
            return true;
        }

        return $user->hasPermission('hr_operations_view');
    }

    protected function companyUsersQuery()
    {
        $query = User::forActiveDirectory();
        if (auth()->user()?->company_id) {
            $query->where('company_id', auth()->user()->company_id);
        }

        return $query;
    }

    protected function authorizeComplaint(Complaint $complaint): void
    {
        $user = Auth::user();
        $companyId = $user?->company_id;
        if ($companyId && $complaint->company_id !== $companyId) {
            abort(403);
        }

        if (! $this->canManageAllComplaints($user) && $complaint->from_user_id !== $user?->id) {
            abort(403, 'You can only access your own complaints.');
        }
    }
}
