<?php

namespace App\Trait;

use App\Actions\Communications\EvaluateContactTriggersAction;
use App\Enum\Contact\TemplateTriggerType;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

trait HasTags {
    /**
     * Attach a tag to the model (creates it if it doesn't exist by name).
     */
    public function attachTag(string|Tag $tag): void {
        if (is_string($tag)) {
            $tag = Tag::firstOrCreate(
                ['name' => $tag],
                ['slug' => \Illuminate\Support\Str::slug($tag)]
            );
        }

        if (!$this->tags()->where('tags.id', $tag->id)->exists()) {
            $this->tags()->attach($tag);
            $this->fireContactTrigger(TemplateTriggerType::TAG_ADDED, $tag);
        }
    }

    /**
     * Get all of the tags for the model.
     */
    public function tags(): MorphToMany {
        return $this->morphToMany(Tag::class, 'taggable');
    }

    /**
     * Detach a tag from the model.
     */
    public function detachTag(string|Tag $tag): void {
        if (is_string($tag)) {
            $tag = Tag::where('name', $tag)->first();
        }

        if ($tag) {
            $this->tags()->detach($tag);
            $this->fireContactTrigger(TemplateTriggerType::TAG_REMOVED, $tag);
        }
    }

    /**
     * Fire a contact template trigger for a tag event.  Failures are swallowed
     * (logged) so tag operations never fail due to trigger-side problems.
     */
    protected function fireContactTrigger(TemplateTriggerType $type, Tag $tag): void
    {
        try {
            app(EvaluateContactTriggersAction::class)(
                $this,
                $type,
                [
                    'tag_id' => $tag->id,
                    'tag_name' => $tag->name,
                    'tag_slug' => $tag->slug ?? null,
                ],
            );
        } catch (\Throwable $e) {
            logger()->error('Contact trigger evaluation failed on tag change', [
                'subject' => static::class,
                'subject_id' => $this->getKey() ?? null,
                'tag' => $tag->name,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Check if the model has a specific tag.
     */
    public function hasTag(string $name): bool {
        return $this->tags()->where('name', $name)->exists();
    }
}