<?php

namespace Modules\ClinicCore\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\ClinicCore\Entities\ClcConfidentialNote;
use Modules\ClinicCore\Entities\ClcPatient;

/**
 * CRUD for polymorphic notes attached to a pet or its owner.
 *
 * Visibility rules:
 *  - "normal"        — anyone who can view the subject (pet/owner) sees it.
 *  - "confidential"  — hidden unless the user has clinic.view_confidential_notes
 *                      OR is the original author.
 *
 * Anyone with clinic.manage_appointments can write a note (normal). Only
 * users who can both write and view_confidential can mark a note confidential.
 */
class ClcConfidentialNoteController extends Controller
{
    use \Modules\ClinicCore\Http\Controllers\Traits\LogsClcActivity;

    private function viewGuard(string $subjectType, int $subjectId, int $businessId): void
    {
        if (!auth()->user()->can('clinic.view_appointments')) {
            abort(403, 'Unauthorized action.');
        }
        // Validate the subject actually belongs to this business.
        if ($subjectType === 'pet') {
            ClcPatient::where('business_id', $businessId)->findOrFail($subjectId);
        } elseif ($subjectType === 'owner') {
            \App\Contact::where('business_id', $businessId)->findOrFail($subjectId);
        } else {
            abort(404);
        }
    }

    private function writeGuard(): void
    {
        if (!auth()->user()->can('clinic.manage_appointments')
            && !auth()->user()->can('clinic.manage_subject_notes')) {
            abort(403, 'Unauthorized action.');
        }
    }

    public function index(Request $request, string $subjectType, int $subjectId)
    {
        $businessId = $request->session()->get('user.business_id');
        $this->viewGuard($subjectType, $subjectId, $businessId);

        $notes = ClcConfidentialNote::with('creator', 'editor')
            ->where('business_id', $businessId)
            ->where('subject_type', $subjectType)
            ->where('subject_id', $subjectId)
            ->visibleTo(auth()->user())
            ->orderByDesc('id')
            ->get();

        return response()->json([
            'notes'           => $notes->map(fn($n) => $this->serialise($n))->all(),
            'can_write'       => auth()->user()->can('clinic.manage_appointments')
                              || auth()->user()->can('clinic.manage_subject_notes'),
            'can_confidential'=> auth()->user()->can('clinic.view_confidential_notes'),
        ]);
    }

    public function store(Request $request, string $subjectType, int $subjectId)
    {
        $this->writeGuard();
        $businessId = $request->session()->get('user.business_id');
        $this->viewGuard($subjectType, $subjectId, $businessId);

        $request->validate([
            'title' => 'nullable|string|max:191',
            'body'  => 'required|string|max:5000',
            'visibility' => 'nullable|in:normal,confidential',
        ]);

        $visibility = $request->visibility === 'confidential' ? 'confidential' : 'normal';
        // Only users who can see confidential notes may mark a note confidential.
        if ($visibility === 'confidential' && !auth()->user()->can('clinic.view_confidential_notes')) {
            $visibility = 'normal';
        }

        $note = ClcConfidentialNote::create([
            'business_id'  => $businessId,
            'subject_type' => $subjectType,
            'subject_id'   => $subjectId,
            'visibility'   => $visibility,
            'title'        => $request->title,
            'body'         => $request->body,
            'created_by'   => auth()->id(),
            'updated_by'   => auth()->id(),
        ]);
        $this->drmLog('create', $note);

        return response()->json(['success' => true, 'msg' => 'Note added.', 'note' => $this->serialise($note->fresh(['creator', 'editor']))]);
    }

    public function update(Request $request, $id)
    {
        $this->writeGuard();
        $businessId = $request->session()->get('user.business_id');
        $note = ClcConfidentialNote::where('business_id', $businessId)->findOrFail($id);

        // Author can always edit own; otherwise needs manage_subject_notes.
        if ($note->created_by !== auth()->id()
            && !auth()->user()->can('clinic.manage_subject_notes')) {
            abort(403, 'You can only edit notes you wrote.');
        }

        $request->validate([
            'title' => 'nullable|string|max:191',
            'body'  => 'required|string|max:5000',
            'visibility' => 'nullable|in:normal,confidential',
        ]);

        $visibility = $request->visibility === 'confidential' ? 'confidential' : 'normal';
        if ($visibility === 'confidential' && !auth()->user()->can('clinic.view_confidential_notes')) {
            $visibility = $note->visibility; // can't promote without the permission
        }

        $note->update([
            'title'      => $request->title,
            'body'       => $request->body,
            'visibility' => $visibility,
            'updated_by' => auth()->id(),
        ]);
        $this->drmLog('update', $note);

        return response()->json(['success' => true, 'msg' => 'Note updated.', 'note' => $this->serialise($note->fresh(['creator', 'editor']))]);
    }

    public function destroy(Request $request, $id)
    {
        $businessId = $request->session()->get('user.business_id');
        $note = ClcConfidentialNote::where('business_id', $businessId)->findOrFail($id);

        if ($note->created_by !== auth()->id()
            && !auth()->user()->can('clinic.manage_subject_notes')) {
            abort(403, 'You can only delete notes you wrote.');
        }

        $this->drmLog('delete', $note);
        $note->delete();
        return response()->json(['success' => true, 'msg' => 'Note removed.']);
    }

    private function serialise(ClcConfidentialNote $n): array
    {
        $fmt = session('business.date_format', 'd M Y');
        return [
            'id'           => $n->id,
            'title'        => $n->title,
            'body'         => $n->body,
            'visibility'   => $n->visibility,
            'is_confidential' => $n->is_confidential,
            'created_by_id'=> $n->created_by,
            'created_by'   => trim((optional($n->creator)->first_name ?? '') . ' ' . (optional($n->creator)->last_name ?? '')),
            'updated_by'   => trim((optional($n->editor)->first_name ?? '')  . ' ' . (optional($n->editor)->last_name  ?? '')),
            'created_at'   => optional($n->created_at)->format($fmt . ' H:i'),
            'updated_at'   => optional($n->updated_at)->format($fmt . ' H:i'),
            'can_edit'     => $n->created_by === auth()->id()
                           || auth()->user()->can('clinic.manage_subject_notes'),
        ];
    }
}
