<?php

namespace App\Models;

use App\Models\Concerns\LogsNotifications;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
 * Meta-Ads campaign. PII columns (name, creative copy, CTWA
 * phone/message, link URL, targeting) are encrypted-at-rest so
 * the database file is unreadable on its own. The Contact model
 * uses the same pattern.
 *
 * Filtering/search needs to hydrate-then-filter for any encrypted
 * column — see `searchByName()` for the pattern. Plain-text
 * categorical columns (status, optimization_goal, objective)
 * stay queryable through scopes.
 */
class MetaCampaign extends Model
{
    use HasFactory, LogsNotifications;

    protected $table = 'meta_campaigns';

    protected $fillable = [
        'user_id',
        'workspace_id',
        'facebook_id',
        // Full CTWA tree — each Meta entity has its own id so we can
        // toggle/edit/delete the whole hierarchy. See migration
        // 2026_05_24_070000_meta_ads_full_ctwa_flow.
        'meta_adset_id',
        'meta_creative_id',
        'meta_ad_id',
        'meta_image_hash',
        'meta_last_error',
        'meta_synced_at',
        'name',
        'objective',
        'optimization_goal',
        'status',
        'type',
        'daily_budget',
        'lifetime_budget',
        'creative_title',
        'creative_body',
        'creative_link_url',
        'creative_image',
        'ctwa_enabled',
        'ctwa_phone',
        'ctwa_message',
        'ctwa_cta',
        'targeting',
        'insights',
        'ad_set_count',
        'ad_count',
    ];

    protected $casts = [
        // Encrypted-at-rest. The DB stores ciphertext; Eloquent
        // decrypts on attribute access. Don't try to LIKE/ORDER
        // BY these columns at the SQL layer — see the helper
        // methods (searchByName, sortByName) that work in PHP
        // after hydration.
        'name'              => 'encrypted',
        'creative_title'    => 'encrypted',
        'creative_body'     => 'encrypted',
        'creative_link_url' => 'encrypted',
        'ctwa_phone'        => 'encrypted',
        'ctwa_message'      => 'encrypted',
        'targeting'         => 'encrypted:array',

        'insights'          => 'array',
        'ctwa_enabled'      => 'boolean',
        'daily_budget'      => 'decimal:2',
        'lifetime_budget'   => 'decimal:2',
        'ad_set_count'      => 'integer',
        'ad_count'          => 'integer',
        'meta_synced_at'    => 'datetime',
        'meta_last_error'   => 'encrypted',
    ];

    public const STATUSES = ['ACTIVE', 'PAUSED', 'SCHEDULED', 'DRAFT', 'FAILED'];

    public const OPTIMIZATION_GOALS = [
        'MESSAGES', 'LINK_CLICKS', 'CONVERSIONS', 'LEAD_GENERATION',
        'REACH', 'BRAND_AWARENESS', 'VIDEO_VIEWS',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class)->withDefault();
    }

    public function scopeForUser(Builder $q, ?int $userId): Builder
    {
        return $userId ? $q->where('user_id', $userId) : $q;
    }

    /** Workspace-shared visibility — every member sees every campaign. */
    public function scopeForCurrentWorkspace(Builder $q): Builder
    {
        $user = auth()->user();
        if (!$user) return $q->whereRaw('1=0');
        $uId  = (int) $user->id;
        $wsId = (int) ($user->current_workspace_id ?? 0);
        return $q->where(function ($qq) use ($wsId, $uId) {
            $qq->where('workspace_id', $wsId)
               ->orWhere(function ($qqq) use ($uId) {
                   $qqq->whereNull('workspace_id')->where('user_id', $uId);
               });
        });
    }

    public function scopeWithStatus(Builder $q, ?string $status): Builder
    {
        if (!$status || $status === 'all') return $q;
        return $q->where('status', strtoupper($status));
    }

    public function scopeWithObjective(Builder $q, ?string $goal): Builder
    {
        if (!$goal || $goal === 'all') return $q;
        return $q->where('optimization_goal', $goal);
    }

    public function scopeInRange(Builder $q, ?string $range): Builder
    {
        return match ($range) {
            '7d'  => $q->where('created_at', '>=', now()->subDays(7)),
            '30d' => $q->where('created_at', '>=', now()->subDays(30)),
            '90d' => $q->where('created_at', '>=', now()->subDays(90)),
            default => $q,
        };
    }

    /**
     * Filter by encrypted name in PHP — DB-side LIKE on
     * ciphertext matches nothing.
     */
    public static function filterByName($items, ?string $term)
    {
        $term = mb_strtolower(trim((string) $term));
        if ($term === '') return $items;
        return $items->filter(fn ($c) => str_contains(mb_strtolower((string) $c->name), $term))->values();
    }

    /**
     * Convenience accessor for the metrics displayed on the card.
     * Falls back to zeros when the campaign hasn't been synced yet.
     */
    public function getMetricsAttribute(): array
    {
        $i = $this->insights ?? [];
        return [
            'spend'       => (float) ($i['spend']       ?? 0),
            'impressions' => (int)   ($i['impressions'] ?? 0),
            'clicks'      => (int)   ($i['clicks']      ?? 0),
            'reach'       => (int)   ($i['reach']       ?? 0),
            'conversions' => (int)   ($i['conversions'] ?? 0),
            'ctr'         => (float) ($i['ctr']         ?? 0),
            'cpc'         => (float) ($i['cpc']         ?? 0),
            'revenue'     => (float) ($i['revenue']     ?? 0),
        ];
    }
}
