<?php

namespace GriffinForms\Includes\Onboarding;

use GriffinForms\Traits\Singleton;

class UserStateRepository extends \GriffinForms\Format
{
    use Singleton;

    public const META_KEY = 'griffinforms_onboarding_state';

    protected $feature_flags;

    protected function setFeatureFlags()
    {
        $this->feature_flags = FeatureFlags::getInstance();
    }

    public function getMetaKey(): string
    {
        return self::META_KEY;
    }

    public function getDefaultState(): array
    {
        return [
            'experience_version' => $this->feature_flags->getExperienceVersion(),
            'status' => 'not_started',
            'current_step' => $this->feature_flags->getFirstEnabledStep(),
            'selected_goal' => '',
            'selected_toggles' => [],
            'selected_placement_action' => '',
            'placement_page_title' => '',
            'placement_target_type' => '',
            'placement_target_id' => 0,
            'placement_result' => [],
            'placement_error' => '',
            'seen' => 0,
            'dismissed' => 0,
            'completed' => 0,
            'last_created_form_id' => 0,
            'entry_source' => '',
            'first_seen_at' => null,
            'dismissed_at' => null,
            'completed_at' => null,
            'updated_at' => null,
        ];
    }

    public function getState(int $user_id = 0): array
    {
        $user_id = $this->normalizeUserId($user_id);
        $state = get_user_meta($user_id, self::META_KEY, true);

        return $this->normalizeState($state);
    }

    public function saveState(array $state, int $user_id = 0): bool
    {
        $user_id = $this->normalizeUserId($user_id);
        $normalized_state = $this->normalizeState($state);
        return update_user_meta($user_id, self::META_KEY, $normalized_state) !== false;
    }

    public function resetStateForCurrentVersion(int $user_id = 0): array
    {
        $state = $this->getDefaultState();
        $this->saveState($state, $user_id);
        return $state;
    }

    public function normalizeState($state): array
    {
        $default_state = $this->getDefaultState();
        if (!is_array($state)) {
            $state = [];
        }

        $normalized_state = array_merge($default_state, $state);
        $allowed_statuses = ['not_started', 'in_progress', 'dismissed', 'completed'];
        $allowed_steps = array_merge($this->feature_flags->getEnabledSteps(), ['success', null]);
        $allowed_entry_sources = ['', 'activation_redirect', 'forms_empty_state', 'manual'];

        $normalized_state['experience_version'] = is_string($normalized_state['experience_version'])
            ? sanitize_text_field($normalized_state['experience_version'])
            : $default_state['experience_version'];

        if (!in_array($normalized_state['status'], $allowed_statuses, true)) {
            $normalized_state['status'] = $default_state['status'];
        }

        if ($normalized_state['current_step'] === null) {
            $normalized_state['current_step'] = null;
        } elseif (is_string($normalized_state['current_step'])) {
            $normalized_state['current_step'] = sanitize_key($normalized_state['current_step']);
        } else {
            $normalized_state['current_step'] = $default_state['current_step'];
        }
        if (!in_array($normalized_state['current_step'], $allowed_steps, true)) {
            $normalized_state['current_step'] = $default_state['current_step'];
        }

        $normalized_state['selected_goal'] = is_string($normalized_state['selected_goal'])
            ? sanitize_key($normalized_state['selected_goal'])
            : '';

        if (!is_array($normalized_state['selected_toggles'])) {
            $normalized_state['selected_toggles'] = [];
        }
        $normalized_state['selected_toggles'] = array_values(array_unique(array_filter(array_map('sanitize_key', $normalized_state['selected_toggles']))));

        $normalized_state['selected_placement_action'] = is_string($normalized_state['selected_placement_action'])
            ? sanitize_key($normalized_state['selected_placement_action'])
            : '';
        $normalized_state['placement_page_title'] = is_string($normalized_state['placement_page_title'])
            ? sanitize_text_field($normalized_state['placement_page_title'])
            : '';
        $normalized_state['placement_target_type'] = is_string($normalized_state['placement_target_type'])
            ? sanitize_key($normalized_state['placement_target_type'])
            : '';
        $normalized_state['placement_target_id'] = absint($normalized_state['placement_target_id']);

        if (!is_array($normalized_state['placement_result'])) {
            $normalized_state['placement_result'] = [];
        }

        if (!is_string($normalized_state['placement_error'])) {
            $normalized_state['placement_error'] = '';
        }
        $normalized_state['placement_error'] = sanitize_text_field($normalized_state['placement_error']);

        $normalized_state['seen'] = (int) (!empty($normalized_state['seen']));
        $normalized_state['dismissed'] = (int) (!empty($normalized_state['dismissed']));
        $normalized_state['completed'] = (int) (!empty($normalized_state['completed']));
        $normalized_state['last_created_form_id'] = absint($normalized_state['last_created_form_id']);


        $normalized_state['entry_source'] = is_string($normalized_state['entry_source'])
            ? sanitize_key($normalized_state['entry_source'])
            : '';
        if (!in_array($normalized_state['entry_source'], $allowed_entry_sources, true)) {
            $normalized_state['entry_source'] = '';
        }

        foreach (['first_seen_at', 'dismissed_at', 'completed_at', 'updated_at'] as $time_key) {
            if (!is_string($normalized_state[$time_key]) || trim($normalized_state[$time_key]) === '') {
                $normalized_state[$time_key] = null;
                continue;
            }

            $normalized_state[$time_key] = sanitize_text_field($normalized_state[$time_key]);
        }

        return $normalized_state;
    }

    protected function normalizeUserId(int $user_id): int
    {
        $user_id = $user_id > 0 ? $user_id : (int) get_current_user_id();
        return $user_id > 0 ? $user_id : 0;
    }
}
