<?php

namespace App\Observers;

use App\Models\AdoptionApplication;
use App\Models\Pet;

class AdoptionApplicationObserver
{
    /**
     * Handle the AdoptionApplication "created" event.
     */
    public function created(AdoptionApplication $adoptionApplication): void
    {
        $this->processPetStatusForApplication($adoptionApplication);
    }

    /**
     * Handle the AdoptionApplication "updated" event.
     */
    public function updated(AdoptionApplication $adoptionApplication): void
    {
        // Handle pet_id changes
        if ($adoptionApplication->wasChanged('pet_id')) {
            $oldPetId = $adoptionApplication->getOriginal('pet_id');
            $newPetId = $adoptionApplication->pet_id;

            if ($oldPetId && $oldPetId !== $newPetId) {
                $this->clearAdoptionDateIfApproved($oldPetId, $adoptionApplication);
                $this->updatePetStatusIfNoOtherActiveApplications($oldPetId, $adoptionApplication->id);
            }

            if ($newPetId) {
                $this->updatePetStatus($newPetId, $adoptionApplication);
            }
        }

        // Handle second_pet_id changes
        if ($adoptionApplication->wasChanged('second_pet_id')) {
            $oldSecondPetId = $adoptionApplication->getOriginal('second_pet_id');
            $newSecondPetId = $adoptionApplication->second_pet_id;

            if ($oldSecondPetId && $oldSecondPetId !== $newSecondPetId) {
                $this->clearAdoptionDateIfApproved($oldSecondPetId, $adoptionApplication);
                $this->updatePetStatusIfNoOtherActiveApplications($oldSecondPetId, $adoptionApplication->id);
            }

            if ($newSecondPetId) {
                $this->updatePetStatus($newSecondPetId, $adoptionApplication);
            }
        }

        // Trigger pet swap if needed
        if ($adoptionApplication->wasChanged('pet_id') || $adoptionApplication->wasChanged('second_pet_id')) {
            $adoptionApplication->swapPetsIfNeeded();
            if ($adoptionApplication->isDirty()) {
                $adoptionApplication->saveQuietly();
            }
        }

        // Handle status changes
        if ($adoptionApplication->wasChanged('status')) {
            $this->processPetStatusForApplication($adoptionApplication);
        }
    }

    /**
     * Handle the AdoptionApplication "deleted" event.
     */
    public function deleted(AdoptionApplication $adoptionApplication): void
    {
        $wasApproved = $adoptionApplication->status === 'approved';

        if ($adoptionApplication->pet_id) {
            if ($wasApproved) {
                $this->clearAdoptionDate($adoptionApplication->pet_id);
            }
            $this->updatePetStatusIfNoOtherActiveApplications($adoptionApplication->pet_id, $adoptionApplication->id);
        }

        if ($adoptionApplication->second_pet_id) {
            if ($wasApproved) {
                $this->clearAdoptionDate($adoptionApplication->second_pet_id);
            }
            $this->updatePetStatusIfNoOtherActiveApplications($adoptionApplication->second_pet_id, $adoptionApplication->id);
        }
    }

    /**
     * Process pet status based on application status for all linked pets.
     */
    private function processPetStatusForApplication(AdoptionApplication $application): void
    {
        if (in_array($application->status, ['cancelled', 'rejected', 'archived'])) {
            $wasApproved = $application->getOriginal('status') === 'approved';

            if ($application->pet_id) {
                if ($wasApproved) {
                    $this->clearAdoptionDate($application->pet_id);
                }
                $this->updatePetStatusIfNoOtherActiveApplications($application->pet_id, $application->id);
            }
            if ($application->second_pet_id) {
                if ($wasApproved) {
                    $this->clearAdoptionDate($application->second_pet_id);
                }
                $this->updatePetStatusIfNoOtherActiveApplications($application->second_pet_id, $application->id);
            }
        } elseif ($application->status === 'approved') {
            if ($application->pet_id) {
                $this->setPetAdopted($application->pet_id);
            }
            if ($application->second_pet_id) {
                $this->setPetAdopted($application->second_pet_id);
            }
        } else {
            // Active statuses (submitted, under_review, interview_scheduled)
            $wasApproved = $application->getOriginal('status') === 'approved';

            if ($application->pet_id) {
                if ($wasApproved) {
                    $this->undoPetAdoption($application->pet_id);
                }
                $this->setPetPending($application->pet_id);
            }
            if ($application->second_pet_id) {
                if ($wasApproved) {
                    $this->undoPetAdoption($application->second_pet_id);
                }
                $this->setPetPending($application->second_pet_id);
            }
        }
    }

    /**
     * Update pet status based on application status.
     */
    private function updatePetStatus(int $petId, AdoptionApplication $application): void
    {
        if ($application->status === 'approved') {
            $this->setPetAdopted($petId);
        } else {
            $this->setPetPending($petId);
        }
    }

    /**
     * Set pet status to adopted and set adoption date.
     */
    private function setPetAdopted(int $petId): void
    {
        $pet = Pet::find($petId);
        if ($pet) {
            $pet->status = 'adopted';
            if (! $pet->adoption_date) {
                $pet->adoption_date = now();
            }
            $pet->save();
        }
    }

    /**
     * Set pet status to pending if not already adopted.
     */
    private function setPetPending(int $petId): void
    {
        $pet = Pet::find($petId);
        if ($pet && $pet->status !== 'adopted') {
            $pet->update(['status' => 'pending']);
        }
    }

    /**
     * Undo an adoption when its application moves back to an active status.
     *
     * Clears the adoption date and lifts the "adopted" status so the pet can be
     * returned to pending while the application is reconsidered.
     */
    private function undoPetAdoption(int $petId): void
    {
        $pet = Pet::find($petId);
        if ($pet && $pet->status === 'adopted') {
            $pet->update([
                'status' => 'pending',
                'adoption_date' => null,
            ]);
        }
    }

    /**
     * Clear adoption_date if the application is approved (pet is being unlinked from its adopting application).
     */
    private function clearAdoptionDateIfApproved(int $petId, AdoptionApplication $application): void
    {
        if ($application->status === 'approved') {
            $this->clearAdoptionDate($petId);
        }
    }

    /**
     * Clear adoption_date for a pet.
     */
    private function clearAdoptionDate(int $petId): void
    {
        $pet = Pet::find($petId);
        if ($pet) {
            $pet->update(['adoption_date' => null]);
        }
    }

    /**
     * Update pet status to available if no other active applications exist.
     * Checks both pet_id and second_pet_id fields.
     */
    private function updatePetStatusIfNoOtherActiveApplications(int $petId, int $applicationId): void
    {
        $hasOtherActiveApplications = AdoptionApplication::query()
            ->where(function ($query) use ($petId) {
                $query->where('pet_id', $petId)
                    ->orWhere('second_pet_id', $petId);
            })
            ->whereNotIn('status', ['cancelled', 'rejected', 'archived'])
            ->where('id', '!=', $applicationId)
            ->exists();

        if (! $hasOtherActiveApplications) {
            $pet = Pet::find($petId);

            // Don't change status to available if pet has an adoption_date
            // (it's already adopted, just has an archived/cancelled/rejected application)
            if ($pet && ! $pet->adoption_date) {
                $pet->update(['status' => 'available']);
            }
        }
    }
}
