<?php

namespace Meliconnect\Meliconnect\Core;

if (! defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

use Meliconnect\Meliconnect\Core\Helpers\Helper;

class SyncProcessor
{
    private $settings;
    private $log_channel = 'sync-cron';
    private $lock_timeout = 300; // 5 min

    public function __construct()
    {
        $this->settings = Helper::getMeliconnectOptions('sync');
    }

    public function run()
    {
        $GLOBALS['meliconnect_sync_running'] = true;

        try {
            

            if (($this->settings['meliconnect_sync_enabled'] ?? 'false') !== 'true') {
                Helper::logData('Sync not enabled', $this->log_channel);
                return;
            }

            if (($this->settings['meliconnect_sync_enable_cron'] ?? 'false') !== 'true') {
                Helper::logData('Sync Cron not enabled', $this->log_channel);
                return;
            }

            $batch = (int) ($this->settings['meliconnect_sync_batch_size'] ?? 20);


            $this->processBatch($batch);
        } finally {
            
            //Helper::logData('--- SyncProcessor END ---', $this->log_channel);
            $GLOBALS['meliconnect_sync_running'] = false;
        }
    }

    private function processBatch($batch)
    {
        global $wpdb;

        $resolver = new SyncDirectionResolver();

        $table = $wpdb->prefix . 'meliconnect_sync_state';

        $items = $wpdb->get_results($wpdb->prepare("
            SELECT *
            FROM {$table}
            WHERE 
                needs_sync = 1
                AND sync_status IN ('pending','error')
                AND (locked_at IS NULL OR locked_at < NOW() - INTERVAL %d SECOND)
                AND retry_count < 5
            ORDER BY priority DESC, updated_at ASC
            LIMIT %d
        ", $this->lock_timeout, $batch));

        if (empty($items)) {
            //Helper::logData('No items to process', $this->log_channel);
            return;
        }
    
        Helper::logData('--- SyncProcessor START ---', $this->log_channel);
        Helper::logData("Processing batch of: {$batch}", $this->log_channel);
    
        foreach ($items as $item) {

            if (!$this->acquireLock($item->id)) {
                Helper::logData("Item {$item->id} is locked", $this->log_channel);
                continue;
            }

            try {

                if (empty($item->direction)) {

                    $direction = $resolver->resolve($item);

                    Helper::logData("Item {$item->id} direction resolved: {$direction}", $this->log_channel);

                    if (!$direction) {
                        throw new \Exception("No direction resolved");
                    }

                    $wpdb->update($table, [
                        'direction' => $direction
                    ], ['id' => $item->id]);


                    $item->direction = $direction;
                }

                $this->processItem($item);
            } finally {
                $this->releaseLock($item->id);
                //Helper::logData("Item {$item->id} released lock to null", $this->log_channel);
                Helper::logData("Item {$item->id} processed", $this->log_channel);
            }
        }

        Helper::logData('--- SyncProcessor END ---', $this->log_channel);
    }


    private function acquireLock($id)
    {
        global $wpdb;

        $updated = $wpdb->query($wpdb->prepare("
            UPDATE {$wpdb->prefix}meliconnect_sync_state
            SET locked_at = NOW(), sync_status = 'processing'
            WHERE id = %d
            AND (locked_at IS NULL OR locked_at < NOW() - INTERVAL %d SECOND)
        ", $id, $this->lock_timeout));

        return $updated === 1;
    }

    private function releaseLock($id)
    {
        global $wpdb;

        $wpdb->update(
            $wpdb->prefix . 'meliconnect_sync_state',
            ['locked_at' => null],
            ['id' => $id]
        );
    }

    private function processItem($item)
    {
        global $wpdb;

        try {

            $service = new SyncService();

            $result = $service->sync($item, $item->direction, $item->sync_type);

            if ($result === true) {

                $wpdb->update(
                    $wpdb->prefix . 'meliconnect_sync_state',
                    [
                        'sync_status'  => 'synced',
                        'needs_sync'   => 0,
                        // NO borrar source acá
                        'last_error'   => null,
                        'direction'    => null,
                        'retry_count'  => 0,
                        'last_sync_at' => current_time('mysql')
                    ],
                    ['id' => $item->id]
                );
            } else {
                throw new \Exception('Sync returned false');
            }
        } catch (\Throwable $e) {

            $wpdb->update(
                $wpdb->prefix . 'meliconnect_sync_state',
                [
                    'sync_status' => 'error',
                    'needs_sync'  => 1,
                    'retry_count' => $item->retry_count + 1,
                    'last_error'  => $e->getMessage()
                ],
                ['id' => $item->id]
            );
        }
    }
}
