<?php

namespace EasyLinkAutomations\Automation;

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

use EasyLinkAutomations\Actions\ActionRegistry;
use EasyLinkAutomations\Models\Automation;
use EasyLinkAutomations\Models\AutomationAction;
use EasyLinkAutomations\Triggers\TriggerRegistry;

/**
 * Manages automations - CRUD operations and validation.
 */
final class AutomationManager
{
    /**
     * Create a new automation.
     *
     * @param array{
     *     title: string,
     *     trigger_slug: string,
     *     trigger_config?: array,
     *     actions: array<array{action_slug: string, config: array}>,
     *     status?: string
     * } $data
     *
     * @return array{success: bool, automation_id?: int, errors?: array}
     */
    public function create(array $data): array
    {
        $errors = $this->validate($data);
        if ($errors) {
            return ['success' => false, 'errors' => $errors];
        }

        $automationId = Automation::create([
            'title'        => sanitize_text_field($data['title']),
            'trigger_type' => $data['trigger_slug'],
            'trigger_data' => wp_json_encode($data['trigger_config'] ?? []),
            'status'       => $data['status'] ?? 'draft',
            'created_by'   => get_current_user_id(),
        ]);

        if (!$automationId) {
            return ['success' => false, 'errors' => ['Failed to create automation']];
        }

        // Create actions
        foreach ($data['actions'] as $index => $action) {
            AutomationAction::create([
                'automation_id' => $automationId,
                'action_slug'   => $action['action_slug'],
                'config'        => wp_json_encode($action['config'] ?? []),
                'action_order'  => $index,
            ]);
        }

        return ['success' => true, 'automation_id' => $automationId];
    }

    /**
     * Update an existing automation.
     */
    public function update(int $id, array $data): array
    {
        $automation = Automation::find($id);
        if (!$automation) {
            return ['success' => false, 'errors' => ['Automation not found']];
        }

        $errors = $this->validate($data, $id);
        if ($errors) {
            return ['success' => false, 'errors' => $errors];
        }

        Automation::update($id, [
            'title'        => sanitize_text_field($data['title']),
            'trigger_type' => $data['trigger_slug'],
            'trigger_data' => wp_json_encode($data['trigger_config'] ?? []),
            'status'       => $data['status'] ?? $automation['status'],
        ]);

        // Replace actions
        AutomationAction::deleteByAutomation($id);

        foreach ($data['actions'] as $index => $action) {
            AutomationAction::create([
                'automation_id' => $id,
                'action_slug'   => $action['action_slug'],
                'config'        => wp_json_encode($action['config'] ?? []),
                'action_order'  => $index,
            ]);
        }

        return ['success' => true, 'automation_id' => $id];
    }

    /**
     * Delete an automation and its actions.
     */
    public function delete(int $id): array
    {
        $automation = Automation::find($id);
        if (!$automation) {
            return ['success' => false, 'errors' => ['Automation not found']];
        }

        AutomationAction::deleteByAutomation($id);
        Automation::delete($id);

        return ['success' => true];
    }

    /**
     * Toggle automation status.
     */
    public function toggleStatus(int $id): array
    {
        $automation = Automation::find($id);
        if (!$automation) {
            return ['success' => false, 'errors' => ['Automation not found']];
        }

        $newStatus = $automation['status'] === 'active' ? 'paused' : 'active';

        Automation::update($id, [
            'status'     => $newStatus,
            'updated_at' => current_time('mysql'),
        ]);

        return ['success' => true, 'status' => $newStatus];
    }

    /**
     * Get automation with all details.
     */
    public function get(int $id): ?array
    {
        $automation = Automation::find($id);
        if (!$automation) {
            return null;
        }

        $automation['trigger_config'] = json_decode($automation['trigger_config'], true) ?? [];
        $automation['actions']        = $this->getActionsWithDetails($id);

        // Add trigger metadata
        $trigger = TriggerRegistry::get($automation['trigger_slug']);
        if ($trigger) {
            $automation['trigger'] = $trigger::toArray();
        }

        return $automation;
    }

    /**
     * List all automations with pagination.
     */
    public function list(int $page = 1, int $perPage = 20): array
    {
        return Automation::paginate($page, $perPage);
    }

    /**
     * Get actions for an automation with metadata.
     */
    private function getActionsWithDetails(int $automationId): array
    {
        $actionRows = AutomationAction::findByAutomation($automationId);
        $result     = [];

        foreach ($actionRows as $row) {
            $action = ActionRegistry::get($row['action_slug']);

            $result[] = [
                'id'           => $row['id'],
                'action_slug'  => $row['action_slug'],
                'action_order' => $row['action_order'],
                'config'       => json_decode($row['config'], true) ?? [],
                'metadata'     => $action ? $action::toArray() : null,
            ];
        }

        usort($result, fn($a, $b) => $a['action_order'] <=> $b['action_order']);

        return $result;
    }

    /**
     * Validate automation data.
     *
     * @return array<string> List of error messages
     */
    private function validate(array $data, ?int $id = null): array
    {
        $errors = [];

        if (empty($data['title'])) {
            $errors[] = 'Title is required';
        }

        if (empty($data['trigger_slug'])) {
            $errors[] = 'Trigger is required';
        } elseif (!TriggerRegistry::has($data['trigger_slug'])) {
            $errors[] = 'Invalid trigger: ' . $data['trigger_slug'];
        }

        if (empty($data['actions']) || !is_array($data['actions'])) {
            $errors[] = 'At least one action is required';
        } else {
            foreach ($data['actions'] as $index => $action) {
                if (empty($action['action_slug'])) {
                    $errors[] = "Action #{$index}: action_slug is required";
                } elseif (!ActionRegistry::has($action['action_slug'])) {
                    $errors[] = "Action #{$index}: Invalid action: " . $action['action_slug'];
                }
            }
        }

        return $errors;
    }
}
