<?php

namespace lucidpen;

if (!defined('ABSPATH'))
    exit;

class PostManager
{
    const CHAT_META_KEY = LCPN_ABBR . '_chat_history';
    const DRAFT_META_KEY = LCPN_ABBR . '_draft_history';
    const USER_KEY_META = LCPN_ABBR . '_encryption_key';
    const OLD_CHAT_META_KEY = 'aoc_chat_history';
    const OLD_DRAFT_META_KEY = 'aoc_draft_history';
    const OLD_USER_KEY_META = 'aoc_encryption_key';

    public const INVALID_POST_ID = 0;

    private string $category;
    private int $post_id;
    private int $user_id;

    public function __construct(string $category = 'Uncategorized', int $post_id = self::INVALID_POST_ID, int $user_id = 0)
    {
        $this->category = $category;
        $this->post_id = $post_id;
        $this->user_id = $user_id ?: get_current_user_id();
    }

    private function ensure_post_id(): void
    {
        if ($this->post_id === self::INVALID_POST_ID) {
            $this->post_id = $this->create_draft_post();
        }
    }

    private function assert_valid_post_id(): void
    {
        if ($this->post_id === self::INVALID_POST_ID) {
            throw new \InvalidArgumentException('Invalid post ID.');
        }
    }

    private function get_category_ids($categories)
    {
        $categories = empty($categories) ? ['Uncategorized'] : (array) $categories;
        $ids = [];

        foreach ($categories as $cat) {
            $term = get_category_by_slug(sanitize_title($cat));
            if (!$term) {
                $id = wp_create_category($cat);
            } else {
                $id = $term->term_id;
            }
            $ids[] = $id;
        }
        return $ids;
    }


    public function create_draft_post(string $title = 'AI Draft (Untitled)'): int
    {
        $post_data = [
            'post_title' => sanitize_text_field($title),
            'post_content' => '',
            'post_status' => 'draft',
            'post_author' => $this->user_id,
            'post_category' => $this->get_category_ids($this->category),
        ];

        $post_id = wp_insert_post($post_data);

        if (is_wp_error($post_id)) {
            Logger::error('AI Draft creation error: ' . $post_id->get_error_message());
            return 0;
        }
        if (!$post_id) {
            Logger::error('AI Draft creation failed: wp_insert_post returned false or 0.');
            return 0;
        }
        return (int) $post_id;
    }


    public function save_post(string $content, $status = 'draft', string $title = null, $category = null): bool
    {
        $this->assert_valid_post_id();

        $args = [
            'ID' => $this->post_id,
            'post_content' => $content,
            'post_status' => $status,
        ];

        if ($title !== null) {
            $args['post_title'] = sanitize_text_field($title);
        }

        if ($category !== null) {
            $args['post_category'] = $this->get_category_ids($category);
        }

        $result = wp_update_post($args, true);

        if (is_wp_error($result)) {
            Logger::error('AI Save Post Error: ' . $result->get_error_message());
            return false;
        }

        return true;
    }

    public function publish_post(): bool
    {
        $this->assert_valid_post_id();

        $result = wp_update_post([
            'ID' => $this->post_id,
            'post_status' => 'publish'
        ], true);

        return !is_wp_error($result);
    }

    public function withdraw_post(): bool
    {
        $this->assert_valid_post_id();

        $result = wp_update_post([
            'ID' => $this->post_id,
            'post_status' => 'draft'
        ], true);

        return !is_wp_error($result);
    }

    public function list_post_revisions(): array
    {
        $this->assert_valid_post_id();

        return wp_get_post_revisions($this->post_id);
    }

    public function get_revision_content(int $revision_id): ?string
    {
        $revision = get_post($revision_id);
        return $revision ? $revision->post_content : null;
    }

    public function delete_post()
    {
        $this->assert_valid_post_id();

        return wp_trash_post($this->post_id);
    }

    public static function list_stale_drafts(int $days, int $user_id): array
    {
        $date_query = gmdate('Y-m-d H:i:s', strtotime("-{$days} days"));

        $query = new \WP_Query([
            'post_type' => 'post',
            'post_status' => 'draft',
            'author' => $user_id,
            'date_query' => [
                [
                    'before' => $date_query,
                    'inclusive' => true,
                ]
            ],
            'posts_per_page' => -1,
            'fields' => 'ids'
        ]);

        return $query->posts;
    }

    public function store_chat_history(array $chat_history): void
    {
        // Logger::info("Storing chat history for post ID: " . $this->post_id);

        $this->ensure_post_id();

        $key = hex2bin($this->get_user_key());
        $iv = random_bytes(16);
        $compressed = gzcompress(json_encode($chat_history), 9);
        $encrypted = openssl_encrypt($compressed, 'aes-256-cbc', $key, 0, $iv);

        $payload = base64_encode($iv) . '::' . base64_encode($encrypted);

        update_post_meta($this->post_id, self::CHAT_META_KEY, $payload);
    }

    public function load_chat_history(): array
    {
        // Logger::info("Loading chat history for post ID: " . $this->post_id);

        if ($this->post_id === self::INVALID_POST_ID) {
            return [];
        }

        $payload = get_post_meta($this->post_id, self::CHAT_META_KEY, true);
        if (empty($payload)) {
            return [];
        }

        $parts = explode('::', $payload);
        if (count($parts) !== 2) {
            return [];
        }

        [$iv_b64, $encrypted_b64] = $parts;
        $iv = base64_decode($iv_b64);
        $encrypted = base64_decode($encrypted_b64);

        $key = hex2bin($this->get_user_key());
        $decompressed = openssl_decrypt($encrypted, 'aes-256-cbc', $key, 0, $iv);
        if ($decompressed === false) {
            return [];
        }

        // Logger::info("Decompressed chat history size: " . strlen($decompressed) . " bytes");

        $json = gzuncompress($decompressed);
        return json_decode($json, true) ?: [];
    }

    public function store_draft_history(array $draft_history): void
    {
        $this->ensure_post_id();

        $compressed = gzcompress(json_encode($draft_history), 9);
        update_post_meta($this->post_id, self::DRAFT_META_KEY, $compressed);
    }

    public function load_draft_history(): array
    {
        if ($this->post_id === self::INVALID_POST_ID) {
            return [];
        }

        $compressed = get_post_meta($this->post_id, self::DRAFT_META_KEY, true);
        if (empty($compressed)) {
            return [];
        }

        $json = gzuncompress($compressed);
        return json_decode($json, true) ?: [];
    }

    private function get_user_key(): string
    {
        $key = get_user_meta($this->user_id, self::USER_KEY_META, true);
        if (empty($key)) {
            $key = bin2hex(random_bytes(32));
            update_user_meta($this->user_id, self::USER_KEY_META, $key);
        }
        return $key;
    }

    public function get_post_id(): int
    {
        return $this->post_id;
    }

    public function get_post(): ?\WP_Post
    {
        if ($this->post_id === self::INVALID_POST_ID) {
            return null;
        }
        return get_post($this->post_id);
    }

    /* ==============================================================
     *  Migration Logic
     * ============================================================== */

    /**
     * Runs once to migrate old meta keys for all posts and users.
     * Safe to re-run manually; normally gated by an option flag.
     */
    public static function migrate_all_existing_meta(): void
    {
        if (get_option('lucidpen_meta_migrated')) {
            Logger::info('LucidPen meta migration already completed — skipping.');
            return;
        }

        $old_new_post_keys = [
            self::OLD_CHAT_META_KEY  => self::CHAT_META_KEY,
            self::OLD_DRAFT_META_KEY => self::DRAFT_META_KEY,
        ];
        $old_new_user_keys = [
            self::OLD_USER_KEY_META  => self::USER_KEY_META,
        ];

        $migrated_posts = 0;
        $migrated_users = 0;

        try {
            // --- Migrate post meta in batches ---
            $paged = 1;
            do {
                $posts = get_posts([
                    'post_type'      => 'post',
                    'post_status'    => 'any',
                    'posts_per_page' => 500,
                    'paged'          => $paged++,
                    'fields'         => 'ids',
                ]);

                foreach ($posts as $post_id) {
                    foreach ($old_new_post_keys as $old => $new) {
                        $old_value = get_post_meta($post_id, $old, true);
                        if (!empty($old_value)) {
                            update_post_meta($post_id, $new, $old_value);
                            delete_post_meta($post_id, $old);
                            $migrated_posts++;
                            Logger::info("Migrated {$old} → {$new} for post {$post_id}");
                        }
                    }
                }
            } while (!empty($posts));
        } catch (\Throwable $e) {
            Logger::error('Post meta migration failed: ' . $e->getMessage());
        }

        try {
            // --- Migrate user meta ---
            $users = get_users(['fields' => ['ID']]);
            foreach ($users as $user) {
                $user_id = $user->ID;
                foreach ($old_new_user_keys as $old => $new) {
                    $old_value = get_user_meta($user_id, $old, true);
                    if (!empty($old_value)) {
                        update_user_meta($user_id, $new, $old_value);
                        delete_user_meta($user_id, $old);
                        $migrated_users++;
                        Logger::info("Migrated {$old} → {$new} for user {$user_id}");
                    }
                }
            }
        } catch (\Throwable $e) {
            Logger::error('User meta migration failed: ' . $e->getMessage());
        }

        // Mark migration complete
        update_option('lucidpen_meta_migrated', gmdate('Y-m-d H:i:s'));
        Logger::info("LucidPen meta migration complete: {$migrated_posts} post(s), {$migrated_users} user(s) updated.");
    }

}
