<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Form;
use App\Models\FormSubmission;
use App\Notifications\FormSubmittedNotification;
use App\Notifications\FormSubmissionReviewedNotification;
use App\Services\AuditService;
use App\Services\Forms\FormSubmissionService;
use App\Services\Forms\FormSubmissionExportService;
use App\Services\HrmsNotificationService;
use Illuminate\Http\Request;

class FormSubmissionController extends Controller
{
    public function __construct(
        protected FormSubmissionService $submissionService,
        protected FormSubmissionExportService $exportService,
        protected AuditService $audit,
        protected HrmsNotificationService $notifier
    ) {}

    public function portal()
    {
        $forms = Form::query()
            ->where('status', 'published')
            ->orderBy('name')
            ->get();

        $mySubmissions = FormSubmission::with('form')
            ->where('user_id', auth()->id())
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        return view('forms.portal', compact('forms', 'mySubmissions'));
    }

    public function fill(Form $form)
    {
        $this->assertPublishedForm($form);

        return view('forms.fill', compact('form'));
    }

    public function store(Request $request, Form $form)
    {
        $this->assertPublishedForm($form);

        $responses = $this->submissionService->validateAndNormalize($form, $request->all());

        $submission = FormSubmission::create([
            'company_id' => auth()->user()->company_id,
            'form_id' => $form->id,
            'user_id' => auth()->id(),
            'responses' => $responses,
            'status' => 'submitted',
        ]);

        $this->audit->log('form_submission.created', $submission, ['form_id' => $form->id]);

        if ($form->company_id) {
            $this->notifier->notifyUsersWithAnyPermission(
                (int) $form->company_id,
                ['documents_view'],
                new FormSubmittedNotification($submission->load(['form', 'user'])),
                [(int) auth()->id()]
            );
        }

        return redirect()->route('forms.portal')->with('success', 'Form submitted successfully.');
    }

    public function index(Request $request)
    {
        abort_unless(auth()->user()?->hasPermission('documents_view'), 403);

        $query = FormSubmission::with(['form', 'user'])->orderByDesc('created_at');

        if ($request->filled('form_id')) {
            $query->where('form_id', $request->integer('form_id'));
        }

        $submissions = $query->paginate(20)->withQueryString();
        $forms = Form::orderBy('name')->get(['id', 'name']);

        return view('forms.submissions.index', compact('submissions', 'forms'));
    }

    public function show(FormSubmission $formSubmission)
    {
        abort_unless(auth()->user()?->hasPermission('documents_view'), 403);
        $this->assertTenantRecord($formSubmission);

        $formSubmission->load(['form', 'user']);

        return view('forms.submissions.show', compact('formSubmission'));
    }

    public function export(Request $request)
    {
        abort_unless(auth()->user()?->hasPermission('documents_view'), 403);

        $companyId = auth()->user()?->company_id;
        $formId = $request->filled('form_id') ? $request->integer('form_id') : null;
        $days = $request->filled('days') ? $request->integer('days') : null;

        return $this->exportService->streamCsv($companyId, $formId, $days);
    }

    public function updateStatus(Request $request, FormSubmission $formSubmission)
    {
        abort_unless(auth()->user()?->hasPermission('documents_view'), 403);
        $this->assertTenantRecord($formSubmission);

        $validated = $request->validate([
            'status' => 'required|in:submitted,approved,rejected,needs_revision',
            'review_notes' => 'nullable|string|max:2000',
        ]);

        $previous = $formSubmission->status;
        $formSubmission->update([
            'status' => $validated['status'],
            'review_notes' => $validated['review_notes'] ?? null,
            'reviewed_by' => auth()->id(),
            'reviewed_at' => now(),
        ]);

        if ($previous !== $formSubmission->status && $formSubmission->user) {
            $formSubmission->user->notify(new FormSubmissionReviewedNotification(
                $formSubmission->load('form'),
                $formSubmission->status
            ));
        }

        $this->audit->log('form_submission.reviewed', $formSubmission, ['status' => $formSubmission->status]);

        return redirect()->route('form-submissions.show', $formSubmission)->with('success', 'Submission updated.');
    }

    protected function assertPublishedForm(Form $form): void
    {
        $companyId = auth()->user()?->company_id;
        if ($companyId && (int) $form->company_id !== (int) $companyId) {
            abort(403);
        }

        abort_unless($form->status === 'published', 404);
        abort_if(empty($form->fields), 422, 'This form has no fields configured yet.');
    }

    protected function assertTenantRecord(FormSubmission $submission): void
    {
        $companyId = auth()->user()?->company_id;
        if ($companyId && (int) $submission->company_id !== (int) $companyId) {
            abort(403);
        }
    }
}
