<?php

namespace OtomaticAi;

use Exception;
use OtomaticAi\Database\Migrator;
use OtomaticAi\Jobs\CheckPublicationsJob;
use OtomaticAi\Jobs\DeleteOldScheduleJob;
use OtomaticAi\Jobs\FetchNetlinkingJob;
use OtomaticAi\Jobs\GenerateNetlinkingJob;
use OtomaticAi\Jobs\GenerateSingleModeJob;
use OtomaticAi\Jobs\GenerateThumbnailJob;
use OtomaticAi\Jobs\PublishPublicationJob;
use OtomaticAi\Jobs\ProcessFailedScheduleJob;
use OtomaticAi\Jobs\ProcessPublicationStepJob;
use OtomaticAi\Jobs\PushProjectsMetricsJob;
use OtomaticAi\Jobs\RunAutopilotJob;
use OtomaticAi\Models\Netlinking;
use OtomaticAi\Models\Publication;
use OtomaticAi\Models\SingleModeGeneration;
use OtomaticAi\Models\ThumbnailTask;
use OtomaticAi\Utils\Amazon\Amazon;
use OtomaticAi\Utils\Auth;
use OtomaticAi\Utils\DataSync;
use OtomaticAi\Utils\Issues;
use OtomaticAi\Utils\Language;
use OtomaticAi\Utils\Linking\Linking;
use OtomaticAi\Utils\Scheduler;
use OtomaticAi\Vendors\Illuminate\Database\Capsule\Manager as Database;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Collection;
use OtomaticAi\Vendors\Illuminate\Support\Str;

class Plugin
{
    public function run()
    {
        $this->database();
        $this->macros();
        $this->schedules();

        if (function_exists("is_admin") && is_admin()) {
            $this->admin();
        } else {
            $this->public();
        }
    }

    private function admin()
    {
        // define menu
        add_action('admin_menu', function () {
            add_menu_page(
                'otomatic.ai',
                'otomatic.ai',
                'manage_options',
                OTOMATIC_AI_NAME,
                function () {
                    wp_enqueue_media();

                    try {
                        DataSync::updateData();
                    } catch (Exception $e) {
                    }

                    $updates = get_plugin_updates();
                    $outdated = isset($updates[OTOMATIC_AI_NAME . "/" . OTOMATIC_AI_NAME . ".php"]);
                    $domain = $this->getDomain();
                    $user = $this->getUser();
                    $data = [
                        "domain" => $domain,
                        "user" => $user,
                        "ajaxurl" => admin_url('admin-ajax.php'),
                        "nonce" => wp_create_nonce(OTOMATIC_AI_NONCE),
                        "version" => ["number" => OTOMATIC_AI_VERSION, "outdated" => $outdated],
                        "public_path" => OTOMATIC_AI_ROOT_URL . 'public',
                        "saas_url" => defined("OTOMATIC_AI_SAAS_URL") ? OTOMATIC_AI_SAAS_URL : null,
                        "saas_domain_url" => defined("OTOMATIC_AI_SAAS_URL") ? OTOMATIC_AI_SAAS_URL . '/domains/' . Arr::get($domain, "id") : null,
                        "admin_url" =>  admin_url(),
                        "authenticated" => Auth::check(),
                        "default_locale" => Language::findFromLocale()->key,
                        "issues" => Issues::detect()
                    ];
                    wp_enqueue_script('otomatic-ai-app', OTOMATIC_AI_ROOT_URL . 'public/js/otomatic-ai.js', ['wp-i18n'], OTOMATIC_AI_VERSION, true);
                    wp_enqueue_style('otomatic-ai-app',  OTOMATIC_AI_ROOT_URL . 'public/css/otomatic-ai.css', [], OTOMATIC_AI_VERSION);
                    wp_set_script_translations('otomatic-ai-app', OTOMATIC_AI_NAME, OTOMATIC_AI_ROOT_PATH . 'languages/');
                    wp_add_inline_script('otomatic-ai-app', 'var otomatic_ai = ' . json_encode($data) . ';', "before");

                    echo "<div id='otomatic-ai-app' class='otomatic-ai-app'></div>";
                },
                OTOMATIC_AI_ROOT_URL . 'public/img/logo-sidebar.png',
                2,
            );

            add_submenu_page(null, "otomatic repair", 'otomatic repair', "manage_options", OTOMATIC_AI_NAME . "-repair", function () {
                Issues::repair();
            });

            if (defined("OTOMATIC_AI_TEST") && OTOMATIC_AI_TEST) {
                add_submenu_page(OTOMATIC_AI_NAME, "otomatic", 'test', "manage_options", OTOMATIC_AI_NAME . "-test", [$this, "test"]);
                add_submenu_page(OTOMATIC_AI_NAME, "otomatic", 'Run Publication', "manage_options", OTOMATIC_AI_NAME . "-run-publication", [$this, "runPublication"]);
                add_submenu_page(OTOMATIC_AI_NAME, "otomatic", 'Run Single Mode', "manage_options", OTOMATIC_AI_NAME . "-run-single-mode", [$this, "runSingleMode"]);
                add_submenu_page(OTOMATIC_AI_NAME, "otomatic", 'Run Thumbnail', "manage_options", OTOMATIC_AI_NAME . "-run-thumbnail", [$this, "runThumbnail"]);
                add_submenu_page(OTOMATIC_AI_NAME, "otomatic", 'Run Netlinking', "manage_options", OTOMATIC_AI_NAME . "-run-netlinking", [$this, "runNetlinking"]);
            }
        });

        // show post row actions
        // add_filter('post_row_actions', function ($actions, $post) {
        //     if (!in_array($post->post_type, ["post", "page"])) return $actions;

        //     $domain = $this->getDomain();
        //     if (empty($domain)) return $actions;

        //     $domainId = Arr::get($domain, "id");
        //     if (empty($domainId)) return $actions;

        //     $post_id = $post->ID;
        //     $title = rawurlencode(get_the_title($post));

        //     $url = admin_url("admin.php?page=otomatic-ai#/projects/create/regenerate/post?ids={$post_id}");
        //     // $url = defined("OTOMATIC_AI_SAAS_URL") ? OTOMATIC_AI_SAAS_URL . "/documents/create/{$domainId}?post_id={$post_id}&title={$title}" : "#";

        //     $actions['open_with_otomatic_ai'] = '<a href="' . esc_url($url) . '" target="_blank">' . __("Regenerate with otomatic.ai", OTOMATIC_AI_NAME) . '</a>';

        //     return $actions;
        // }, 10, 2);

        // add_action('add_meta_boxes', function () {
        //     add_meta_box(
        //         'open_with_saas',
        //         'otomatic.ai',
        //         function ($post) {

        //             $domain = $this->getDomain();
        //             if (empty($domain)) return "";

        //             $domainId = Arr::get($domain, "id");
        //             if (empty($domainId)) return "";

        //             $post_id = $post->ID;
        //             $title = rawurlencode(get_the_title($post));

        //             $url = admin_url("admin.php?page=otomatic-ai#/projects/create/regenerate/post?ids={$post_id}");
        //             // $url = defined("OTOMATIC_AI_SAAS_URL") ? OTOMATIC_AI_SAAS_URL . "/documents/create/{$domainId}?post_id={$post_id}&title={$title}" : "#";

        //             echo '<div class="misc-pub-section" style="text-align: center;">';
        //             echo '<a href="' . esc_url($url) . '" target="_blank" style="display: inline-flex; align-items: center; gap: 8px; background-color: #000; color: #fff; padding: 6px 12px; border-radius: 4px; text-decoration: none;">';
        //             echo '<svg width="16" height="16" viewBox="0 0 16 16" fill="white" xmlns="http://www.w3.org/2000/svg">';
        //             echo '<circle cx="8" cy="8" r="6" stroke="white" stroke-width="2" fill="none" />';
        //             echo '</svg>';
        //             echo '<span>' . __("Regenerate", OTOMATIC_AI_NAME) . '</span>';
        //             echo '</a>';
        //             echo '</div>';
        //         },
        //         ['post', 'page'],
        //         'side',
        //         'default'
        //     );
        // });

        // add bulk action
        add_filter('bulk_actions-edit-post', function ($actions) {
            $actions['regenerate_with_otomatic_ai'] = __("Regenerate with otomatic.ai", OTOMATIC_AI_NAME);
            return $actions;
        });
        add_filter('bulk_actions-edit-page', function ($actions) {
            $actions['regenerate_with_otomatic_ai'] = __("Regenerate with otomatic.ai", OTOMATIC_AI_NAME);
            return $actions;
        });

        add_filter('handle_bulk_actions-edit-post', function ($redirect_to, $doaction, $post_ids) {
            if ($doaction !== 'regenerate_with_otomatic_ai') {
                return $redirect_to;
            }

            $ids = implode(',', $post_ids);
            return admin_url('admin.php?page=otomatic-ai#/projects/create/regenerate/post?ids=' . urlencode($ids));
        }, 10, 3);

        add_filter('handle_bulk_actions-edit-page', function ($redirect_to, $doaction, $post_ids) {
            if ($doaction !== 'regenerate_with_otomatic_ai') {
                return $redirect_to;
            }

            $ids = implode(',', $post_ids);
            return admin_url('admin.php?page=otomatic-ai#/projects/create/regenerate/page?ids=' . urlencode($ids));
        }, 10, 3);

        add_action('admin_footer-edit.php', function () {
            // only show on post edit page
            $screen = get_current_screen();
            if ($screen->post_type !== 'post') return;

            $gif_url = OTOMATIC_AI_ROOT_URL . 'public/img/bulk-regenerate.gif';
?>
            <style>
                #otomatic-ai-bulk-regenerate {
                    position: fixed;
                    z-index: 9999;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    background: rgba(0, 0, 0, 0.7);
                    display: none;
                    align-items: center;
                    justify-content: center;
                }

                #otomatic-ai-bulk-regenerate .content {
                    background: white;
                    padding: 20px;
                    max-width: 600px;
                    border-radius: 8px;
                    box-shadow: 0 0 10px black;
                }

                #otomatic-ai-bulk-regenerate .content img {
                    max-width: 100%;
                    height: auto;
                }

                #otomatic-ai-bulk-regenerate .close {
                    margin-top: 15px;
                    display: inline-block;
                    background: #0073aa;
                    color: white;
                    padding: 8px 12px;
                    text-decoration: none;
                    border-radius: 4px;
                }

                #otomatic-ai-bulk-regenerate .close:hover {
                    background: #005077;
                }

                #otomatic-ai-bulk-regenerate-button {
                    margin-left: 10px;
                    height: 30px;
                    font-size: 13px;
                    padding: 0 12px;
                    vertical-align: middle;
                    background: #000;
                    color: #fff;
                    border: none;
                    border-radius: 3px;
                    cursor: pointer;
                }

                #otomatic-ai-bulk-regenerate-button:hover {
                    background: #222;
                }
            </style>
            <div id="otomatic-ai-bulk-regenerate">
                <div class="content">
                    <p><strong>Comment regénérer plusieurs articles en une fois ?</strong></p>
                    <img src="<?php echo esc_url($gif_url); ?>">
                    <br>
                    <a href="#" class="close">J'ai compris</a>
                </div>
            </div>
            <script>
                jQuery(document).ready(function($) {

                    const $topNav = $('.tablenav.top .actions').first();
                    if ($topNav.length) {
                        const $btn = $('<button type="button" id="otomatic-ai-bulk-regenerate-button">Régénérer avec otomatic.ai</button>');
                        $topNav.append($btn);

                        $btn.on('click', function() {
                            $('#otomatic-ai-bulk-regenerate').css('display', 'flex').hide().fadeIn();
                        });
                    }

                    $('#otomatic-ai-bulk-regenerate .close').on('click', function(e) {
                        e.preventDefault();
                        $('#otomatic-ai-bulk-regenerate').fadeOut();
                        history.replaceState(null, '', location.href.replace(/([&?])show_bulk_regenerate_notice=1(&|$)/, '$1').replace(/\?$/, ''));
                    });
                });
            </script>
            <?php
            if (isset($_GET['show_bulk_regenerate_notice'])) {
            ?>
                <script>
                    jQuery(document).ready(function($) {
                        $('#otomatic-ai-bulk-regenerate').css('display', 'flex').hide().fadeIn();
                    });
                </script>
        <?php
            };
        });



        require_once plugin_dir_path(__FILE__) . '../routes/ajax.php';
    }

    private function public()
    {
        add_filter('the_content', [Linking::class, 'filter'], 1);
        add_shortcode('otomatic-ai-amazon-products', [Amazon::class, 'shortcode']);
        add_action('wp_enqueue_scripts', [Amazon::class, 'enqueueStyles']);

        require_once plugin_dir_path(__FILE__) . '../routes/rest.php';
    }

    private function macros()
    {
        /**
         * Clean a string text
         * 
         * @param  string  $str
         * @return string
         */
        Str::macro('clean', function ($str) {

            if (is_array($str)) {
                $str = implode(" ", Arr::flatten($str));
            }
            $str = explode("\n", $str);
            $str = array_map(function ($line) {
                $line = strip_tags($line);
                $line = trim($line, " \"'\)\]\}\(\[\{\t\n\r\0\x0B");
                $line = preg_replace('/^[\d\.\-\#]+/', '', $line);
                $line = trim($line, " \"'\)\]\}\(\[\{\t\n\r\0\x0B");
                return $line;
            }, $str);

            return implode("\n", $str);
        });

        /**
         * Key an associative array by a field or using a callback.
         *
         * @param  array  $array
         * @param  callable|array|string  $keyBy
         * @return array
         */
        Arr::macro('keyBy', function ($array, $keyBy) {
            return Collection::make($array)->keyBy($keyBy)->all();
        });

        /**
         * Group an associative array by a field or using a callback.
         *
         * @param  array  $array
         * @param  callable|array|string  $keyBy
         * @return array
         */
        Arr::macro('groupBy', function ($array, $groupBy) {
            return Collection::make($array)->groupBy($groupBy)->toArray();
        });

        /**
         * Run a map over each of the items in the array.
         *
         * @param  array  $array
         * @param  callable  $callback
         * @return array
         */
        Arr::macro('map', function (array $array, callable $callback) {
            $keys = array_keys($array);

            $items = array_map($callback, $array, $keys);

            return array_combine($keys, $items);
        });

        /**
         * Key an associative array by a field or using a callback.
         *
         * @param  array  $array
         * @param  callable|array|string  $keyBy
         * @return array
         */
        Arr::macro('partition', function ($array, $length) {
            $listLength = count($array);
            $partLength = floor($listLength / $length);
            $partrem = $listLength % $length;
            $partition = array();
            $mark = 0;

            for ($px = 0; $px < $length; $px++) {
                $incr = ($px < $partrem) ? $partLength + 1 : $partLength;
                $partition[$px] = array_slice($array, $mark, $incr);
                $mark += $incr;
            }

            return $partition;
        });

        /**
         * Merge an array with a default array.
         *
         * @param  array  $array
         * @param  array  $default
         * @return array
         */
        Arr::macro('merge', function (array $array, array $default = []) {
            $merged = [];
            foreach ($default as $key => $value) {
                if (is_array($value) && Arr::isAssoc($value)) {
                    $merged[$key] = Arr::merge(Arr::get($array, $key, []), $value);
                } else if (is_array($value) && Arr::isList($value)) {
                    $merged[$key] = Arr::get($array, $key, $value);
                } else {
                    $merged[$key] = Arr::get($array, $key, $value);
                }
            }

            return $merged;
        });

        /**
         * Get the values of an array.
         *
         * @param  array  $array
         * @return array
         */
        Arr::macro('values', function (array $array) {
            return array_values($array);
        });
    }

    private function getDomain()
    {
        $domain = null;

        try {
            $domain = Auth::domain();
        } catch (Exception $e) {
        }

        return $domain;
    }

    private function getUser()
    {
        $user = null;

        try {
            $user = Auth::user();
        } catch (Exception $e) {
        }

        return $user;
    }

    private function database()
    {
        // database manager
        $database = new Database();
        $hostParts = explode(":", DB_HOST);
        $database->addConnection([
            'driver' => 'mysql',
            'host' =>  Arr::get($hostParts, 0),
            'port' => Arr::get($hostParts, 1, "3306"),
            'database' => DB_NAME,
            'username' => DB_USER,
            'password' => DB_PASSWORD,
            'charset' => defined("DB_CHARSET") ? DB_CHARSET : 'utf8',
            'collation' => defined("DB_COLLATE") && strlen(DB_COLLATE) > 0 ? DB_COLLATE : null
        ]);
        $database->setAsGlobal();
        $database->bootEloquent();
    }

    public function activate()
    {
        Migrator::run();
    }

    private function schedules()
    {
        // init
        Scheduler::init();

        // register
        Scheduler::register("run_autopilot_job", function () {
            $job = new RunAutopilotJob;
            $job->handle();
        });
        Scheduler::register("check_publications_to_publish", function () {
            $job = new CheckPublicationsJob;
            $job->handle();
        });
        Scheduler::register("process_failed_shedules", function () {
            $job = new ProcessFailedScheduleJob;
            $job->handle();
        });
        Scheduler::register("delete_old_schedules", function () {
            $job = new DeleteOldScheduleJob;
            $job->handle();
        });
        Scheduler::register("publish_publication", function ($publication) {
            $publication = Publication::find($publication);
            if ($publication) {
                $job = new PublishPublicationJob($publication);
                $job->handle();
            }
        });
        ProcessPublicationStepJob::register();
        // Scheduler::register("process_publication_next_step", function ($id) {
        //     $publication = Publication::find($id);
        //     $step = Arr::get($publication, "generation_state.current_step");
        //     if ($step) {
        //         $job = new ProcessPublicationStepJob($publication);
        //         $job->handle();
        //     }
        // });
        Scheduler::register("generate_single_mode", function ($id) {
            $generation = SingleModeGeneration::find($id);
            if ($generation) {
                $job = new GenerateSingleModeJob($generation);
                $job->handle();
            }
        });
        Scheduler::register("generate_netlinking", function ($id) {
            $netlinking = Netlinking::find($id);
            if ($netlinking) {
                $job = new GenerateNetlinkingJob($netlinking);
                $job->handle();
            }
        });
        Scheduler::register("fetch_netlinking_job", function () {
            $job = new FetchNetlinkingJob;
            $job->handle();
        });
        Scheduler::register("generate_thumbnail", function ($id) {
            $thumbnailTask = ThumbnailTask::find($id);
            if ($thumbnailTask) {
                $job = new GenerateThumbnailJob($thumbnailTask);
                $job->handle();
            }
        });
        PushProjectsMetricsJob::register();

        // run
        Scheduler::schedule("run_autopilot_job", Scheduler::EVERY_HOURS);
        Scheduler::schedule("check_publications_to_publish", Scheduler::EVERY_MINUTES);
        Scheduler::schedule("process_failed_shedules", Scheduler::EVERY_MINUTES);
        Scheduler::schedule("delete_old_schedules", Scheduler::EVERY_FIFTEEN_MINUTES);
        Scheduler::schedule("fetch_netlinking_job", Scheduler::EVERY_FIVE_MINUTES);
        Scheduler::schedule(PushProjectsMetricsJob::HOOK, Scheduler::EVERY_HOURS);
    }

    public function test()
    {
        echo "<pre>";
        echo "</pre>";
    }

    public function runPublication()
    {
        $id = Arr::get($_GET, 'publication');
        if (!empty($id)) {
            $publication = Publication::find($id);
            $publication->status = "idle";
            $publication->save();
            echo "<pre>";
            $job = new PublishPublicationJob($publication);
            $job->handle();
            echo "</pre>";
        }
        ?>
        <form method="GET">
            <label for="publication">Publication ID</label>
            <input id="publication" name="publication" type="text" value="<?php echo $id; ?>" />
            <input name="page" type="hidden" value="<?php echo $_GET["page"]; ?>" />
            <button tupe="submit">Run</button>
        </form>
    <?php
    }

    public function runSingleMode()
    {
        $id = Arr::get($_GET, 'id');
        if (!empty($id)) {
            $generation = SingleModeGeneration::find($id);
            $generation->status = "idle";
            $generation->save();
            echo "<pre>";
            $job = new GenerateSingleModeJob($generation);
            $job->handle();
            echo "</pre>";
        }
    ?>
        <form method="GET">
            <label for="id">Generation ID</label>
            <input id="id" name="id" type="text" value="<?php echo $id; ?>" />
            <input name="page" type="hidden" value="<?php echo $_GET["page"]; ?>" />
            <button tupe="submit">Run</button>
        </form>
    <?php
    }

    public function runThumbnail()
    {
        $id = Arr::get($_GET, 'id');
        if (!empty($id)) {
            $publication = Publication::find($id);
            $thumbnailTask = new ThumbnailTask();
            $thumbnailTask->publication_id = $publication->id;
            $thumbnailTask->model = "flux_1_dev";
            $thumbnailTask->override = true;
            $thumbnailTask->status = "idle";
            $thumbnailTask->save();
            echo "<pre>";
            $job = new GenerateThumbnailJob($thumbnailTask);
            $job->handle();
            echo "</pre>";
        }
    ?>
        <form method="GET">
            <label for="id">Publication ID</label>
            <input id="id" name="id" type="text" value="<?php echo $id; ?>" />
            <input name="page" type="hidden" value="<?php echo $_GET["page"]; ?>" />
            <button tupe="submit">Run</button>
        </form>
    <?php
    }

    public function runNetlinking()
    {
        $id = Arr::get($_GET, 'id');
        if (!empty($id)) {
            $netlinking = Netlinking::find($id);
            $netlinking->status = "idle";
            $netlinking->save();
            echo "<pre>";
            $job = new GenerateNetlinkingJob($netlinking);
            $job->handle();
            print_r($netlinking->logs);
            echo "</pre>";
        }
    ?>
        <form method="GET">
            <label for="id">Netlinking ID</label>
            <input id="id" name="id" type="text" value="<?php echo $id; ?>" />
            <input name="page" type="hidden" value="<?php echo $_GET["page"]; ?>" />
            <button tupe="submit">Run</button>
        </form>
<?php
    }
}
