<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;

class Ticket extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'business_id',
        'contact_owner_id',
        'primary_contact_id',
        'employee_id',
        'account_id',
        'source_id',
        'campaign_id',
        'topic',
        'description',
        'comments',
        'contact_name',
        'phone',
        'email',
        'social_media',
        'priority_id',
        'stage_id',
        'date_time',
        'moved_to_type',
        'moved_to_id',
        'moved_at',
    ];

    protected function casts(): array
    {
        return ['date_time' => 'datetime', 'moved_at' => 'datetime'];
    }


    public function ticketLanguages()
    {
        return $this->hasMany(TicketLanguage::class);
    }

    public function ticketProducts()
    {
        return $this->hasMany(TicketProduct::class);
    }

    public function assignedUser()
    {
        return $this->belongsTo(User::class, 'contact_owner_id');
    }

    public function campaign() { return $this->belongsTo(Campaign::class); }
    public function account() { return $this->belongsTo(Account::class); }
    public function primaryContact() { return $this->belongsTo(Contact::class, 'primary_contact_id'); }
    public function activities() { return $this->hasMany(Activity::class); }
    public function assignments() { return $this->morphMany(CrmAssignment::class, 'assignable'); }
    public function statusHistory() { return $this->morphMany(CrmStatusHistory::class, 'statusable'); }
    public function files() { return $this->morphMany(CrmFile::class, 'fileable'); }
    public function moveHistories() { return $this->hasMany(TicketMoveHistory::class); }
    public function assignmentHistories() { return $this->hasMany(TicketAssignmentHistory::class); }

    public function recordMove(string $destinationType, Model $destination, ?string $reason = null): void
    {
        DB::transaction(function () use ($destinationType, $destination, $reason) {
            $ticket = static::query()->lockForUpdate()->findOrFail($this->getKey());
            abort_if($ticket->moved_at, 409, 'This Ticket has already been moved and cannot be moved again.');
            abort_unless(in_array($destinationType, ['contact', 'lead', 'deal'], true), 422, 'Unsupported Ticket destination.');
            abort_if(isset($destination->business_id) && (int) $destination->business_id !== (int) $ticket->business_id, 403);
            $ticket->loadMissing(['ticketLanguages', 'ticketProducts', 'activities', 'assignments', 'files']);

            $snapshot = [
                'account_id' => $ticket->account_id,
                'primary_contact_id' => $ticket->primary_contact_id,
                'campaign_id' => $ticket->campaign_id,
                'source_id' => $ticket->source_id,
                'language_ids' => $ticket->ticketLanguages->pluck('language_id')->values(),
                'product_ids' => $ticket->ticketProducts->pluck('product_id')->values(),
                'activity_ids' => $ticket->activities->pluck('id')->values(),
                'assignment_user_ids' => $ticket->assignments->pluck('user_id')->values(),
                'file_ids' => $ticket->files->pluck('id')->values(),
            ];

            $ticket->moveHistories()->create([
                'business_id' => $ticket->business_id,
                'destination_type' => $destinationType,
                'destination_id' => $destination->getKey(),
                'moved_by' => auth()->id(),
                'reason' => $reason,
                'relationship_snapshot' => $snapshot,
            ]);

            $destinationColumn = ['contact' => 'contact_id', 'lead' => 'lead_id', 'deal' => 'deal_id'][$destinationType] ?? null;
            if ($destinationColumn) {
                $ticket->activities()->update([$destinationColumn => $destination->getKey()]);
            }

            $ticket->update([
                'moved_to_type' => $destinationType,
                'moved_to_id' => $destination->getKey(),
                'moved_at' => now(),
            ]);
            $this->setRawAttributes($ticket->getAttributes(), true);
        });
    }
}
