<?php

namespace GriffinForms\Includes\Pipelines\Accounts;

use GriffinForms\Config;

class ActionStateStore
{
    public function getAccountsState(int $submission_id): array
    {
        $meta = $this->getSubmissionMeta($submission_id);
        $state = $meta[Contract::SUBMISSION_META_KEY] ?? [];
        if (!is_array($state)) {
            return [];
        }

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

    public function saveAccountsState(int $submission_id, array $accounts_state): bool
    {
        if ($submission_id <= 0) {
            return false;
        }

        $meta = $this->getSubmissionMeta($submission_id);
        $meta[Contract::SUBMISSION_META_KEY] = $this->normalizeAccountsState($accounts_state);

        return $this->updateSubmissionMeta($submission_id, $meta);
    }

    public function updateAction(int $submission_id, string $action_id, array $changes): bool
    {
        if ($submission_id <= 0 || $action_id === '' || empty($changes)) {
            return false;
        }

        $meta = $this->getSubmissionMeta($submission_id);
        $state = isset($meta[Contract::SUBMISSION_META_KEY]) && is_array($meta[Contract::SUBMISSION_META_KEY])
            ? $meta[Contract::SUBMISSION_META_KEY]
            : [];

        if (empty($state['setups']) || !is_array($state['setups'])) {
            return false;
        }

        $updated = false;
        foreach ($state['setups'] as $setup_index => $setup) {
            if (empty($setup['targets']) || !is_array($setup['targets'])) {
                continue;
            }

            foreach ($setup['targets'] as $target_index => $target) {
                if (!is_array($target) || (string) ($target['action_id'] ?? '') !== $action_id) {
                    continue;
                }

                $target = array_replace($target, $changes);
                $target['updated_at'] = gmdate('c');
                $state['setups'][$setup_index]['targets'][$target_index] = $target;
                $updated = true;
                break 2;
            }
        }

        if (!$updated) {
            return false;
        }

        $state['updated_at'] = gmdate('c');
        $meta[Contract::SUBMISSION_META_KEY] = $this->normalizeAccountsState($state);
        return $this->updateSubmissionMeta($submission_id, $meta);
    }

    public function getAction(int $submission_id, string $action_id): array
    {
        if ($submission_id <= 0 || $action_id === '') {
            return [];
        }

        $state = $this->getAccountsState($submission_id);
        if (empty($state['setups']) || !is_array($state['setups'])) {
            return [];
        }

        foreach ($state['setups'] as $setup) {
            if (empty($setup['targets']) || !is_array($setup['targets'])) {
                continue;
            }

            foreach ($setup['targets'] as $target) {
                if (is_array($target) && (string) ($target['action_id'] ?? '') === $action_id) {
                    return $target;
                }
            }
        }

        return [];
    }

    private function getSubmissionMeta(int $submission_id): array
    {
        if ($submission_id <= 0) {
            return [];
        }

        global $wpdb;
        $table = Config::getInstance()->getTable('submission');
        $raw_meta = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT submission_meta FROM %i WHERE id = %d",
                $table,
                $submission_id
            )
        );

        if (!is_string($raw_meta) || $raw_meta === '') {
            return [];
        }

        $decoded = json_decode($raw_meta, true);
        return is_array($decoded) ? $decoded : [];
    }

    private function updateSubmissionMeta(int $submission_id, array $meta): bool
    {
        global $wpdb;
        $table = Config::getInstance()->getTable('submission');
        $updated = $wpdb->update(
            $table,
            ['submission_meta' => wp_json_encode($meta)],
            ['id' => $submission_id],
            ['%s'],
            ['%d']
        );

        return $updated !== false;
    }

    private function normalizeAccountsState(array $state): array
    {
        if (empty($state['setups']) || !is_array($state['setups'])) {
            unset($state['summary']);
            return $state;
        }

        $state['summary'] = $this->buildAccountsSummary($state);
        return $state;
    }

    private function buildAccountsSummary(array $state): array
    {
        $created_user_ids = [];
        $updated_user_ids = [];
        $accepted_noop_user_ids = [];
        $all_user_ids = [];
        $result_counts = [];
        $status_counts = [];
        $setup_count = 0;
        $target_count = 0;

        foreach (($state['setups'] ?? []) as $setup) {
            if (!is_array($setup)) {
                continue;
            }

            $setup_count++;
            $targets = isset($setup['targets']) && is_array($setup['targets']) ? $setup['targets'] : [];

            foreach ($targets as $target) {
                if (!is_array($target)) {
                    continue;
                }

                $target_count++;

                $result = sanitize_key((string) ($target['result'] ?? ''));
                if ($result !== '') {
                    if (!isset($result_counts[$result])) {
                        $result_counts[$result] = 0;
                    }
                    $result_counts[$result]++;
                }

                $status = sanitize_key((string) ($target['status'] ?? ''));
                if ($status !== '') {
                    if (!isset($status_counts[$status])) {
                        $status_counts[$status] = 0;
                    }
                    $status_counts[$status]++;
                }

                $user_id = isset($target['user_id']) ? absint($target['user_id']) : 0;
                if ($user_id <= 0) {
                    continue;
                }

                $all_user_ids[$user_id] = $user_id;

                if ($result === 'created') {
                    $created_user_ids[$user_id] = $user_id;
                } elseif ($result === 'updated') {
                    $updated_user_ids[$user_id] = $user_id;
                } elseif ($result === 'accepted_noop') {
                    $accepted_noop_user_ids[$user_id] = $user_id;
                }
            }
        }

        return [
            'created_user_ids' => array_values($created_user_ids),
            'updated_user_ids' => array_values($updated_user_ids),
            'accepted_noop_user_ids' => array_values($accepted_noop_user_ids),
            'all_user_ids' => array_values($all_user_ids),
            'counts' => [
                'setups' => $setup_count,
                'targets' => $target_count,
                'created_users' => count($created_user_ids),
                'updated_users' => count($updated_user_ids),
                'accepted_noop_users' => count($accepted_noop_user_ids),
                'all_users' => count($all_user_ids),
                'by_result' => $result_counts,
                'by_status' => $status_counts,
            ],
        ];
    }
}
