<?php

namespace OtomaticAi\Models;

use OtomaticAi\Casts\Language;
use OtomaticAi\Observers\ProjectObserver;
use OtomaticAi\Utils\Image;
use OtomaticAi\Utils\ProjectSettings\ProjectSettingsFactory;
use OtomaticAi\Vendors\Illuminate\Database\Eloquent\Model;
use OtomaticAi\Vendors\Illuminate\Events\Dispatcher;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Database\Eloquent\Builder;

class Project extends Model
{
    static $version = 2;

    protected $fillable = ["name", "language", "type", "enabled", "input", "modules", "planning"];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = [
        'is_complete',
    ];

    protected $casts = [
        'language' => Language::class,
        'enabled' => 'boolean',
        'input' => 'array',
        'modules' => 'array',
        'planning' => 'array',
        'metrics' => 'array',
    ];

    /**
     * Create a new Eloquent model instance.
     *
     * @param  array  $attributes
     * @return void
     */
    public function __construct(array $attributes = [])
    {
        global $wpdb;

        $this->table = $wpdb->prefix . 'otomatic_ai_projects';
        parent::__construct($attributes);
    }

    public static function boot()
    {
        parent::boot();

        if (!static::getEventDispatcher()) {
            static::setEventDispatcher(new Dispatcher());
        }
        static::observe(new ProjectObserver());
    }

    /**
     * Get the publications for the project.
     */
    public function publications()
    {
        return $this->hasMany(Publication::class);
    }

    public function firstPublishedPublication()
    {
        return $this->hasOne(Publication::class)
            ->where("status", "success")
            ->orderBy('created_at', 'asc');
    }

    /**
     * Get the persona that owns the project.
     */
    public function persona()
    {
        return $this->belongsTo(Persona::class);
    }

    /**
     * Indicate if the project has publish all his publication
     */
    public function getIsCompleteAttribute()
    {
        return Arr::get($this->metrics, 'idle', 0) + Arr::get($this->metrics, 'pending', 0) === 0;
    }

    public function getModulesAttribute()
    {
        $newModules = self::makeModules($this->type, json_decode($this->attributes["modules"], true));

        // set post type to page if project type is siloing
        if ($this->type === "siloing") {
            Arr::set($newModules, "wordpress.post_type", "page");
        }

        // try to set the wordpress.author_id if is not set and persona is set
        if ($this->persona_id !== null && empty(Arr::get($newModules, "wordpress.author_id"))) {
            $persona = $this->persona;
            if (!empty($persona)) {
                $author = $persona->user;
                if (!empty($author)) {
                    Arr::set($newModules, "wordpress.author_id", $author->ID);
                }
            }
        }

        // disable custom links
        Arr::set($newModules, "automatic.custom_links.enabled", false);

        return $newModules;
    }

    private static function transformOldModules(array $modules)
    {
        if (Arr::get($modules, "_version", 1) < 2) {
            return array_replace_recursive([
                "models" => [
                    "text" => Arr::get($modules, "text.model", "gpt-4o-mini"),
                    "image" => Image::imageProviderAndModelToModel(Arr::get($modules, "image.service"), Arr::get($modules, "image.settings." . Arr::get($modules, "image.service") . ".model")),
                ],
                "content" => [
                    "writing_style" => Arr::get($modules, "text.writing_style"),
                    "sources" => [
                        "enabled" => Arr::get($modules, "text.sources.enabled", false),
                        "no_follow" => Arr::get($modules, "text.sources.no_follow", false),
                        "blank" => Arr::get($modules, "text.sources.blank", false),
                    ],
                    "custom_instructions" => [
                        "images" => Arr::get($modules, "image.custom_instructions"),
                    ],
                    "blocks" => !Arr::get($modules, "automatic_template.enabled", false) ? Arr::get($modules, "blocks", []) : [],
                    "automatic" => [
                        "enabled" => Arr::get($modules, "automatic_template.enabled", false) || empty(Arr::get($modules, "blocks", [])),
                        "images" => [
                            "enabled" => !Arr::get($modules, "automatic_template.disable_image_generation", false),
                        ],
                        "youtube" => [
                            "enabled" => !Arr::get($modules, "automatic_template.disable_youtube_generation", false),
                        ],
                        "embeds" => [
                            "enabled" => !Arr::get($modules, "automatic_template.disable_embeds_generation", false),
                        ],
                        "internal_links" => [
                            "enabled" => !Arr::get($modules, "automatic_template.disable_internal_links", false),
                        ],
                        "external_links" => [
                            "enabled" => !Arr::get($modules, "automatic_template.disable_external_links", false),
                        ],

                    ],
                ],
                "wordpress" => [
                    "thumbnail" => [
                        "enabled" => Arr::get($modules, "image.thumbnail.enabled", false),
                    ],
                    "seo_title" => [
                        "enabled" => Arr::get($modules, "wordpress.yoast_seo.title.enabled", false) || Arr::get($modules, "wordpress.rank_math.title.enabled", false) || Arr::get($modules, "wordpress.seo_title.enabled", false),
                        "emojis" => [
                            "enabled" => Arr::get($modules, "wordpress.yoast_seo.title.emojis.enabled", false) || Arr::get($modules, "wordpress.rank_math.title.emojis.enabled", false) || Arr::get($modules, "wordpress.seo_title.emojis.enabled", false),
                        ]
                    ],
                    "seo_description" => [
                        "enabled" => Arr::get($modules, "wordpress.yoast_seo.description.enabled", false) || Arr::get($modules, "wordpress.rank_math.description.enabled", false) || Arr::get($modules, "wordpress.seo_description.enabled", false),
                    ],
                ],
            ], $modules);
        }

        return $modules;
    }

    public static function makeModules(string $type, array $modules)
    {
        $modules = self::transformOldModules($modules);

        $settings = ProjectSettingsFactory::make($type);
        $newModules = array_replace_recursive($settings->defaults(), $modules);

        // convert old models to new models
        $newModules = self::convertOldTextModels($newModules);
        $newModules = self::convertOldImageModels($newModules);

        // force disable embeds
        Arr::set($newModules, "content.automatic.embeds.enabled", false);

        // remove embeds blocks
        Arr::set($newModules, "content.blocks", array_values(Arr::where(Arr::get($newModules, "content.blocks", []), function ($block) {
            return !in_array(Arr::get($block, "block"), ["facebook", "twitter", "instagram", "tiktok"]);
        })));

        return $newModules;
    }

    /**
     * Scope a query to only include completed publications.
     */
    public function scopeCompleted(Builder $query): void
    {
        $query->whereRaw("JSON_UNQUOTE(JSON_EXTRACT(metrics, '$.idle')) = ?", [0])
            ->whereRaw("JSON_UNQUOTE(JSON_EXTRACT(metrics, '$.pending')) = ?", [0]);
    }

    public function refreshMetrics()
    {
        $this->metrics = $this->publications()->toBase()
            ->selectRaw("count(*) as total")
            ->selectRaw("count(IF(status = 'idle', 1, null)) as idle")
            ->selectRaw("count(IF(status = 'pending', 1, null)) as pending")
            ->selectRaw("count(IF(status = 'success', 1, null)) as success")
            ->selectRaw("count(IF(status = 'failed', 1, null)) as failed")
            ->first();
        $this->save();
    }

    /**
     * Convert old image models to new image models
     */
    public static function convertOldImageModels(array $modules)
    {
        // set ai model to default if no longer available
        Arr::set($modules, "models.image", self::getCorrectImageModel(Arr::get($modules, "models.image", "flux_1_dev")));

        return $modules;
    }

    /**
     * Convert old text models to new text models
     */
    public static function convertOldTextModels(array $modules)
    {
        // set ai model to default if no longer available
        Arr::set($modules, "models.text", self::getCorrectTextModel(Arr::get($modules, "models.text", "gpt-4o-mini")));

        return $modules;
    }

    public static function getCorrectTextModel(?string $model = null)
    {
        if (empty($model)) {
            return "gpt-4.1-mini";
        }

        $override = [

            // openai
            "gpt-4-5" => "gpt-5",
            "o1-mini" => "o4-mini",

            // anthropic
            "claude-3-5-sonnet" => "claude-5-sonnet",
            "claude-3-7-sonnet" => "claude-5-sonnet",
            "claude-4-sonnet" => "claude-5-sonnet",
            "claude-4-5-sonnet" => "claude-5-sonnet",
            "claude-4-6-sonnet" => "claude-5-sonnet",
            "claude-4-opus" => "claude-5-opus",
            "claude-4-1-opus" => "claude-5-opus",
            "claude-4-5-opus" => "claude-5-opus",
            'claude-4-6-opus' => 'claude-5-opus',
            'claude-4-7-opus' => 'claude-5-opus',
            'claude-4-8-opus' => 'claude-5-opus',

            // google
            "gemini-3.5-flash" => "gemini-3.6-flash",
            "gemini-2-pro" => "gemini-2.5-pro",
            "gemini-2-flash" => "gemini-2.5-flash",
            "gemini-2-flash-lite" => "gemini-2.5-flash-lite",
            "gemini-2-flash-thinking" => "gemini-2.5-flash",
            "gemini-3-pro" => "gemini-3.1-pro",

            // grok
            "grok-2" => "grok-4",
            "grok-3" => "grok-4",
            "grok-3-mini" => "grok-4.1-fast",
            "grok-3-fast" => "grok-4.1-fast",
            "grok-3-mini-fast" => "grok-4.1-fast",
            "grok-4-fast" => "grok-4.1-fast",

            // deepseek
            "deepseek-chat" => "deepseek-v4-flash",
            "deepseek-reasoner" => "deepseek-v4-flash",
        ];

        if (isset($override[$model])) {
            return $override[$model];
        }

        if (!in_array($model, [
            // automatic
            "automatic-1",
            "automatic-2",
            "automatic-3",

            // openai
            "gpt-5.6-sol",
            "gpt-5.6-terra",
            "gpt-5.6-luna",
            "gpt-5.5",
            "gpt-5.4",
            "gpt-5.4-mini",
            "gpt-5.4-nano",
            "gpt-5.2",
            "gpt-5.1",
            "gpt-5",
            "gpt-5-mini",
            "gpt-5-nano",
            "gpt-4.1",
            "gpt-4.1-mini",
            "gpt-4.1-nano",
            "gpt-4o",
            "gpt-4o-mini",
            "o4-mini",
            "o3",
            "o3-mini",
            "o1",

            // mistral
            "mistral-large",

            // anthropic
            "claude-5-opus",
            "claude-5-sonnet",
            "claude-4-5-haiku",

            // google
            "gemini-3.6-flash",
            "gemini-3.5-flash",
            "gemini-3.5-flash-lite",
            "gemini-3.1-pro",
            "gemini-3.1-flash-lite",
            "gemini-3-flash",
            "gemini-2.5-pro",
            "gemini-2.5-flash",
            "gemini-2.5-flash-lite",

            // deepseek
            "deepseek-v4-flash",

            // grok
            "grok-4",
            "grok-4.1-fast",
        ])) {
            return "gpt-4.1-mini";
        }

        return $model;
    }

    public static function getCorrectImageModel(?string $model = null)
    {
        if (empty($model)) {
            return "gpt_image_1_medium";
        }

        $override = [
            "dall_e_2" => "gpt_image_1_medium",
            "dall_e_3" => "gpt_image_1_medium",
            "ideogram_v_1" => "ideogram_v_1_turbo",
            "ideogram_v_1_turbo" => "ideogram_v_1_turbo",
            "ideogram_v_2" => "ideogram_v_2_turbo",
            "ideogram_v_2_turbo" => "ideogram_v_2_turbo",
            "ideogram_v_2a" => "ideogram_v_2a_turbo",
            "ideogram_v_2a_turbo" => "ideogram_v_2a_turbo",
            "stable_diffusion_sdxl" => "stable_diffusion_core",
            "stable_diffusion_sd3_medium" => "stable_diffusion_sd3_5_medium",
            "stable_diffusion_sd3_large_turbo" => "stable_diffusion_sd3_5_large_turbo",
            "stable_diffusion_sd3_large" => "stable_diffusion_sd3_5_large",
            "flux_1_pro" => "flux_1_1_pro",
            "grok_2_image" => "grok_imagine_pro",
        ];

        if (isset($override[$model])) {
            return $override[$model];
        }

        return $model;
    }
}
