<?php

namespace Pixeldev\SquareWooSync\REST;

use Pixeldev\SquareWooSync\Abstracts\RESTController;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;

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

/**
 * Tracks first-run wizard state. Stored in a single option so we can resume
 * the user mid-flow if they leave and come back, and so the React layout
 * knows whether to redirect to /onboarding on initial load.
 */
class OnboardingController extends RESTController
{
    protected $namespace = 'sws/v1';
    protected $base      = 'onboarding';

    public const OPTION_KEY = 'sws_onboarding';

    public function register_routes()
    {
        register_rest_route($this->namespace, '/' . $this->base, [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'get_state'],
                'permission_callback' => [$this, 'check_permission'],
            ],
            [
                'methods'             => WP_REST_Server::EDITABLE,
                'callback'            => [$this, 'update_state'],
                'permission_callback' => [$this, 'check_permission'],
            ],
        ]);

        register_rest_route($this->namespace, '/' . $this->base . '/reset', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'reset_state'],
                'permission_callback' => [$this, 'check_permission'],
            ],
        ]);
    }

    public function get_state(): WP_REST_Response
    {
        return new WP_REST_Response($this->read_state(), 200);
    }

    public function update_state(WP_REST_Request $request): WP_REST_Response
    {
        $params = $request->get_json_params();
        if (!is_array($params)) {
            $params = [];
        }

        $state = $this->read_state();

        if (array_key_exists('step', $params)) {
            $state['step'] = max(0, (int) $params['step']);
        }

        if (array_key_exists('completed', $params)) {
            $completed          = (bool) $params['completed'];
            $state['completed'] = $completed;
            if ($completed && empty($state['completed_at'])) {
                $state['completed_at'] = time();
            }
            if (!$completed) {
                $state['completed_at'] = 0;
            }
        }

        if (array_key_exists('skipped', $params)) {
            $state['skipped'] = (bool) $params['skipped'];
            if ($state['skipped']) {
                $state['completed']    = true;
                $state['completed_at'] = $state['completed_at'] ?: time();
            }
        }

        if (array_key_exists('banner_dismissed', $params)) {
            $state['banner_dismissed'] = (bool) $params['banner_dismissed'];
        }

        if (array_key_exists('discovery', $params) && is_array($params['discovery'])) {
            $incoming = $params['discovery'];
            foreach (['has_square_products', 'has_woo_products'] as $key) {
                if (array_key_exists($key, $incoming)) {
                    $state['discovery'][$key] =
                        null === $incoming[$key] ? null : (bool) $incoming[$key];
                }
            }
        }

        if (empty($state['started_at'])) {
            $state['started_at'] = time();
        }

        update_option(self::OPTION_KEY, $state, false);

        return new WP_REST_Response($state, 200);
    }

    public function reset_state(): WP_REST_Response
    {
        delete_option(self::OPTION_KEY);
        return new WP_REST_Response($this->read_state(), 200);
    }

    private function read_state(): array
    {
        $defaults = [
            'completed'        => false,
            'skipped'          => false,
            'step'             => 0,
            'started_at'       => 0,
            'completed_at'     => 0,
            'banner_dismissed' => false,
            'discovery'        => [
                'has_square_products' => null,
                'has_woo_products'    => null,
            ],
        ];

        // `false` (the default) means the record was never written. Existing
        // installs upgrading into this version land here, so we infer
        // completion from the presence of a configured location and skip the
        // wizard for them.
        $saved = get_option(self::OPTION_KEY, false);

        if (false === $saved) {
            $inferred = $this->infer_existing_install();
            if ($inferred) {
                $state = array_merge($defaults, $inferred);
                update_option(self::OPTION_KEY, $state, false);
                return $state;
            }
            $saved = [];
        }

        if (!is_array($saved)) {
            $saved = [];
        }

        $state = array_merge($defaults, $saved);

        if (!is_array($state['discovery'])) {
            $state['discovery'] = $defaults['discovery'];
        } else {
            $state['discovery'] = array_merge(
                $defaults['discovery'],
                $state['discovery']
            );
        }

        return $state;
    }

    /**
     * If the plugin already looks configured (a Square location is selected),
     * treat the wizard as completed for this site so existing users aren't
     * redirected into a setup flow they don't need.
     */
    private function infer_existing_install(): array
    {
        $settings = get_option('square-woo-sync_settings', []);
        if (!is_array($settings)) {
            return [];
        }

        $has_location = !empty($settings['location']);
        if (!$has_location) {
            return [];
        }

        $now = time();
        return [
            'completed'        => true,
            'skipped'          => false,
            'step'             => 0,
            'started_at'       => $now,
            'completed_at'     => $now,
            'banner_dismissed' => true,
        ];
    }
}
