<?php

namespace App\Livewire\Issues;

use App\Models\Feature;
use App\Models\Issue;
use App\Models\Project;
use App\Notifications\IssueAssignedNotification;
use App\Notifications\IssueReportedNotification;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Component;

#[Layout('layouts.app')]
class IssueForm extends Component
{
    public Project $project;

    public ?Issue $issue = null;   // null = create, set = edit

    public $projectUsers = [];

    // Form fields
    public $title = '';

    public $description = '';

    public $status = 'open';

    public $priority = 'medium';

    public $type = 'defect';

    public $assignedTo = '';

    public $resolutionNotes = '';

    // Optional context (e.g. when reporting from a map feature)
    public $featureId = null;

    public $inspectionId = null;

    public $featureName = null;   // shown when the issue is pre-linked to a map element

    public function mount(Project $project, ?Issue $issue = null)
    {
        $this->project = $project;

        if ($issue) {
            abort_unless($issue->project_id === $project->id, 404);
        }
        abort_unless($this->canAccessProject() && Auth::user()->can($issue ? 'edit issues' : 'create issues'), 403);

        $this->projectUsers = $project->users()->orderBy('name')->get();

        if ($issue) {
            $this->issue = $issue;
            $this->title = $issue->title;
            $this->description = $issue->description ?? '';
            $this->status = $issue->status;
            $this->priority = $issue->priority;
            $this->type = $issue->type ?? 'defect';
            $this->assignedTo = $issue->assigned_to ?? '';
            $this->resolutionNotes = $issue->resolution_notes ?? '';
            $this->featureId = $issue->feature_id;
            $this->inspectionId = $issue->inspection_id;
            $this->featureName = $issue->feature?->name;
        } elseif ($featureId = request()->integer('feature')) {
            // Pre-link to a map element when reporting from the project map.
            $feature = Feature::with('layer.phase')->find($featureId);
            if ($feature && $feature->layer?->phase?->project_id === $project->id) {
                $this->featureId = $feature->id;
                $this->featureName = $feature->name;
            }
        }
    }

    private function canAccessProject(): bool
    {
        $user = Auth::user();

        return $user->can('manage all')
            || $this->project->users()->where('user_id', $user->id)->exists();
    }

    protected function rules(): array
    {
        return [
            'title' => 'required|string|max:255',
            'description' => 'nullable|string',
            'status' => 'required|in:'.implode(',', Issue::STATUSES),
            'priority' => 'required|in:'.implode(',', Issue::PRIORITIES),
            'type' => 'required|in:'.implode(',', Issue::TYPES),
            'assignedTo' => 'nullable|exists:users,id',
            'resolutionNotes' => 'nullable|string',
        ];
    }

    public function save()
    {
        abort_unless(Auth::user()->can($this->issue ? 'edit issues' : 'create issues'), 403);
        $this->validate();

        $payload = [
            'title' => $this->title,
            'description' => $this->description,
            'status' => $this->status,
            'priority' => $this->priority,
            'type' => $this->type,
            'feature_id' => $this->featureId,
            'inspection_id' => $this->inspectionId,
            'assigned_to' => $this->assignedTo ?: null,
            'resolution_notes' => $this->resolutionNotes ?: null,
        ];

        // Keep resolved_at in sync with the status
        $payload['resolved_at'] = in_array($this->status, ['resolved', 'closed']) ? now() : null;

        if ($this->issue) {
            $previousAssignee = $this->issue->assigned_to;
            // Don't overwrite an existing resolved date
            if ($this->issue->resolved_at && in_array($this->status, ['resolved', 'closed'])) {
                unset($payload['resolved_at']);
            }
            $this->issue->update($payload);
            $issue = $this->issue;

            // Notify a newly assigned user (when it changed and isn't the current actor).
            if ($issue->assigned_to && $issue->assigned_to !== $previousAssignee && $issue->assigned_to !== Auth::id()) {
                $issue->assignee?->notify(new IssueAssignedNotification($issue));
            }
        } else {
            $issue = Issue::create(array_merge($payload, [
                'project_id' => $this->project->id,
                'reported_by' => Auth::id(),
            ]));

            $issue->load(['feature', 'assignee']);
            $creator = $this->project->creator;
            if ($creator && $creator->id !== Auth::id()) {
                $creator->notify(new IssueReportedNotification($issue));
            }
            if ($issue->assignee && $issue->assignee->id !== Auth::id()) {
                $issue->assignee->notify(new IssueReportedNotification($issue));
            }
        }

        session()->flash('message', $this->issue ? 'Incidencia actualizada' : 'Incidencia creada');

        return $this->redirectRoute('projects.issues.show', ['project' => $this->project, 'issue' => $issue], navigate: true);
    }

    public function render()
    {
        return view('livewire.issues.issue-form');
    }
}
