<?php

namespace App\Models;

use App\Models\Concerns\HasEngineScope;
use App\Models\Concerns\LogsNotifications;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;

/**
 * Flow — auto-replies & chatbot graph saved by the React builder.
 *
 * Adapted from D:\wadesk_2806\New folder\app\Models\Flow.php with two
 * adjustments to match the rest of this app:
 *   - flow_name + flow_data are encrypted-at-rest like every other PII
 *     column (Contact / Broadcast / WaTemplate pattern)
 *   - LogsNotifications writes a Notification row on each create/update/delete
 *
 * `flow_data` is stored as encrypted JSON. The accessor returns the
 * decoded array. The optional `flow_file_path` mirrors the old project's
 * uploads/flows/flow_{id}.json fallback so the Node.js bridge can read
 * the graph from disk if it doesn't talk to the DB directly.
 */
class Flow extends Model
{
    use HasEngineScope, HasFactory, SoftDeletes, LogsNotifications;

    /**
     * Auto-stamp `provider` on create from the workspace's active engine.
     */
    protected static function booted(): void
    {
        static::creating(function (self $f) {
            if (empty($f->provider) && !empty($f->workspace_id)) {
                try {
                    $f->provider = \App\Services\WorkspaceEngine::for((int) $f->workspace_id);
                } catch (\Throwable $e) {}
            }
        });
    }

    protected $fillable = [
        'user_id',
        'workspace_id',
        'provider',
        'flow_name',
        'flow_file_path',
        'flow_data',
        'category',
        'is_published',
        'is_active',
        'published_at',
        // Audience trigger — replaces the old drip_campaigns table. The
        // trigger node inside flow_data drives keyword matching at runtime;
        // these columns let Laravel query "which flows want this tag /
        // group" without decrypting flow_data.
        'trigger_kind',
        'trigger_value',
        'trigger_device_id',
    ];

    protected $casts = [
        'flow_name'    => 'encrypted',
        'flow_data'    => 'encrypted',
        'is_published' => 'boolean',
        'is_active'    => 'boolean',
        'published_at' => 'datetime',
    ];

    public const TRIGGER_KINDS = ['keyword', 'tag_added', 'group_join', 'manual_enroll'];

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

    public function subscribers()
    {
        return $this->hasMany(FlowSubscriber::class);
    }

    public function connectedDevices()
    {
        return $this->hasMany(FlowConnectedDevice::class);
    }

    public function activeDevices()
    {
        return $this->hasMany(FlowConnectedDevice::class)->where('status', 'active');
    }

    /**
     * Legacy per-user scope — kept for backward compatibility. Prefer
     * `scopeForCurrentWorkspace` for any new caller. NULL-owner rows
     * are NOT returned (no admin-seeded global flows exist), so a row
     * with NULL user_id can no longer leak to every user.
     */
    public function scopeForUser($q, ?int $userId)
    {
        return $q->where('user_id', $userId);
    }

    /**
     * Workspace-shared visibility — every member of the current
     * workspace sees every flow in it. Pre-migration rows fall back
     * to the original creator only.
     */
    public function scopeForCurrentWorkspace($q)
    {
        $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);
               });
        });
    }

    /**
     * Return flow_data decoded to an array. Falls back to the file
     * mirror if the DB column is empty (matches the old behaviour).
     */
    public function getDecodedFlowDataAttribute(): array
    {
        $raw = $this->flow_data;
        if (is_array($raw))  return $raw;
        if (is_string($raw) && $raw !== '') {
            $decoded = json_decode($raw, true);
            if (is_array($decoded)) return $decoded;
        }
        if ($this->flow_file_path) {
            $abs = public_path($this->flow_file_path);
            if (is_file($abs)) {
                $decoded = json_decode((string) file_get_contents($abs), true);
                if (is_array($decoded)) return $decoded;
            }
        }
        return ['flowNodes' => [], 'flowEdges' => []];
    }

    /**
     * Mirror the flow JSON to disk for the Node bridge.
     */
    public function saveFlowFile($flowData): string
    {
        $directory = public_path('uploads/flows');
        if (!is_dir($directory)) {
            @mkdir($directory, 0755, true);
        }
        $relativePath = 'uploads/flows/flow_' . $this->id . '.json';
        $absolute     = public_path($relativePath);
        @file_put_contents($absolute, json_encode($flowData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
        $this->forceFill(['flow_file_path' => $relativePath])->saveQuietly();
        return $relativePath;
    }

    public function deleteFlowFile(): void
    {
        if ($this->flow_file_path) {
            $abs = public_path($this->flow_file_path);
            if (is_file($abs)) @unlink($abs);
        }
    }

    protected static function boot(): void
    {
        parent::boot();
        static::deleting(function (Flow $flow) {
            $flow->deleteFlowFile();
        });
    }
}
