<?php

namespace App\Controllers;

use App\Libraries\PhoneNumber;
use App\Models\ComplaintModel;
use App\Models\GuestModel;
use App\Models\NotificationModel;
use App\Models\UserModel;
use Config\Lookups;

/**
 * Complaint & service recovery tracking — entirely missing before (see
 * the requirements audit). Open to manager/front_desk/fnb, unlike most
 * modules that sit in just one of those two existing route groups: a
 * complaint can originate from any department, so this gets its own
 * `role:manager,front_desk,fnb` route group rather than being bolted
 * onto either existing one.
 *
 * Workflow mirrors MaintenanceController's open -> in_progress ->
 * completed shape, extended to the one extra real stage this needs:
 * open -> assigned -> resolved -> followed_up ("assignment", per the
 * requirement, isn't just "someone's working on it" the way maintenance
 * treats in_progress — it's a distinct handoff step with its own
 * assignee, and "resolved" and "the promised follow-up actually
 * happened" are two different facts worth recording separately).
 */
class ComplaintController extends BaseController
{
    public function index()
    {
        $complaints = new ComplaintModel();
        $tab        = $this->request->getGet('tab') ?: 'all';

        $builder = $complaints->withDetails();

        if (in_array($tab, ['open', 'assigned', 'resolved', 'followed_up'], true)) {
            $builder->where('complaints.status', $tab);
        }

        $list = $builder->orderBy('complaints.created_at', 'desc')->findAll();

        return view('complaints/index', [
            'pageTitle'    => 'Service Recovery',
            'pageSubtitle' => 'Log, assign, and resolve guest complaints.',
            'tab'          => $tab,
            'complaints'   => $list,
            'stats'        => [
                'open'        => (new ComplaintModel())->countByStatus('open'),
                'assigned'    => (new ComplaintModel())->countByStatus('assigned'),
                'resolved'    => (new ComplaintModel())->countByStatus('resolved'),
                'followedUp'  => (new ComplaintModel())->countByStatus('followed_up'),
            ],
            'lookups' => new Lookups(),
        ]);
    }

    public function new()
    {
        $guestId = (int) $this->request->getGet('guest_id');
        $guest   = $guestId > 0 ? (new GuestModel())->find($guestId) : null;

        return view('complaints/form', [
            'pageTitle' => 'Log Complaint',
            'guest'     => $guest,
            'staff'     => (new UserModel())->where('is_active', 1)->orderBy('full_name')->findAll(),
            'lookups'   => new Lookups(),
        ]);
    }

    public function create()
    {
        $guestId = (int) $this->request->getPost('guest_id');

        if ($guestId <= 0) {
            return redirect()->back()->withInput()->with('error', 'Look up and select the guest this complaint is about.');
        }

        $complaints = new ComplaintModel();
        $data = [
            'guest_id'    => $guestId,
            'category'    => $this->request->getPost('category'),
            'description' => $this->request->getPost('description'),
            'priority'    => $this->request->getPost('priority') ?: 'medium',
            'assigned_to' => $this->request->getPost('assigned_to') ?: null,
            'status'      => $this->request->getPost('assigned_to') ? 'assigned' : 'open',
            'reported_by' => $this->currentUserId(),
        ];

        if (! $complaints->insert($data)) {
            return $this->redirectWithModelErrors($complaints);
        }

        $complaintId = $complaints->getInsertID();
        $guest       = (new GuestModel())->find($guestId);

        (new NotificationModel())->notify(
            'New complaint logged for ' . $guest->full_name . ' (' . ($this->lookups()->complaintCategories[$data['category']]['label'] ?? $data['category']) . ').',
            site_url('complaints/' . $complaintId),
        );

        $this->logActivity('guest', 'Logged a complaint for "' . $guest->full_name . '".');

        return redirect()->to('complaints/' . $complaintId)->with('success', 'Complaint logged.');
    }

    public function show(int $id)
    {
        $complaint = (new ComplaintModel())->withDetails()->where('complaints.id', $id)->first();

        if ($complaint === null) {
            return redirect()->to('complaints')->with('error', 'Complaint not found.');
        }

        return view('complaints/show', [
            'pageTitle' => 'Complaint #' . $id,
            'complaint' => $complaint,
            'staff'     => (new UserModel())->where('is_active', 1)->orderBy('full_name')->findAll(),
            'lookups'   => new Lookups(),
        ]);
    }

    public function assign(int $id)
    {
        $complaints = new ComplaintModel();

        if ($complaints->find($id) === null) {
            return redirect()->to('complaints')->with('error', 'Complaint not found.');
        }

        $assignedTo = (int) $this->request->getPost('assigned_to');

        if ($assignedTo <= 0) {
            return redirect()->to('complaints/' . $id)->with('error', 'Choose who this is assigned to.');
        }

        $complaints->update($id, ['assigned_to' => $assignedTo, 'status' => 'assigned']);
        $this->logActivity('guest', "Assigned complaint #{$id}.");

        return redirect()->to('complaints/' . $id)->with('success', 'Assigned.');
    }

    public function resolve(int $id)
    {
        $complaints = new ComplaintModel();

        if ($complaints->find($id) === null) {
            return redirect()->to('complaints')->with('error', 'Complaint not found.');
        }

        $complaints->update($id, [
            'status'           => 'resolved',
            'resolution_notes' => $this->request->getPost('resolution_notes'),
            'resolved_at'      => date('Y-m-d H:i:s'),
        ]);
        $this->logActivity('guest', "Resolved complaint #{$id}.");

        return redirect()->to('complaints/' . $id)->with('success', 'Marked resolved.');
    }

    public function followUp(int $id)
    {
        $complaints = new ComplaintModel();

        if ($complaints->find($id) === null) {
            return redirect()->to('complaints')->with('error', 'Complaint not found.');
        }

        $complaints->update($id, [
            'status'          => 'followed_up',
            'follow_up_notes' => $this->request->getPost('follow_up_notes'),
            'follow_up_at'    => date('Y-m-d H:i:s'),
        ]);
        $this->logActivity('guest', "Logged follow-up for complaint #{$id}.");

        return redirect()->to('complaints/' . $id)->with('success', 'Follow-up logged.');
    }

    /** Same reasoning as PosOrderController::lookupGuest() — fnb shouldn't need /guests access just to log a complaint. */
    public function lookupGuest()
    {
        $phone      = (string) $this->request->getGet('phone');
        $normalized = PhoneNumber::normalize($phone);

        if ($normalized === null) {
            return $this->response->setJSON(['found' => false]);
        }

        $guest = (new GuestModel())->where('phone', $normalized)->first();

        if ($guest === null) {
            return $this->response->setJSON(['found' => false]);
        }

        return $this->response->setJSON([
            'found' => true,
            'guest' => ['id' => $guest->id, 'full_name' => $guest->full_name, 'phone' => $guest->phone],
        ]);
    }

    private function lookups(): Lookups
    {
        return new Lookups();
    }
}
