<?php

namespace PloverCRM\Modules\Automations\Endpoints;

use PloverCRM\Core\Api\AbstractEndpoint;
use PloverCRM\Modules\Automations\Services\AutomationApiSerializer;
use PloverCRM\Modules\Automations\Services\AutomationDefinitionBuilder;
use PloverCRM\Modules\Automations\Services\AutomationRepository;
use PloverCRM\Modules\Automations\Services\AutomationRunRepository;
use PloverCRM\Modules\Automations\Services\DefinitionValidator;
use PloverCRM\Modules\Integrations\Services\AutomationsLogger;
use PloverCRM\Modules\Integrations\Services\GoogleAdsConversionActionResolver;
use PloverCRM\Modules\Integrations\Services\GoogleAdsLeadUploadStatusService;
use WP_REST_Request;

class AutomationsEndpoint extends AbstractEndpoint
{
    public function getRoute(): string
    {
        return '/automations(?:/(?P<id>\d+))?';
    }

    public function getMethod()
    {
        return ['GET', 'POST', 'PUT', 'DELETE'];
    }

    public function handle(WP_REST_Request $request)
    {
        $method = $request->get_method();
        $automationId = absint($request->get_param('id'));

        switch ($method) {
            case 'GET':
                return $automationId > 0
                    ? $this->getAutomation($automationId)
                    : $this->listAutomations();

            case 'POST':
                return $this->saveAutomation($request, 0);

            case 'PUT':
                return $this->saveAutomation($request, $automationId);

            case 'DELETE':
                return $this->deleteAutomation($automationId);
        }

        return $this->error('The requested method is not supported for this endpoint', 405);
    }

    private function listAutomations()
    {
        $automations = array_map(
            [AutomationApiSerializer::class, 'summary'],
            AutomationRepository::all()
        );

        return $this->success([
            'automations' => $automations,
        ]);
    }

    private function getAutomation(int $automationId)
    {
        $automation = AutomationRepository::find($automationId);

        if (!$automation) {
            return $this->error('Automation not found.', 404, 'automation_not_found');
        }

        $runs = AutomationRunRepository::getRecentForAutomation($automationId);

        return $this->success(
            AutomationApiSerializer::detail($automation, $runs)
        );
    }

    private function saveAutomation(WP_REST_Request $request, int $automationId)
    {
        $payload = $request->get_json_params();
        if (!is_array($payload)) {
            $payload = $request->get_params();
        }

        $existingAutomation = $automationId > 0 ? AutomationRepository::find($automationId) : null;
        if ($automationId > 0 && !$existingAutomation) {
            return $this->error('Automation not found.', 404, 'automation_not_found');
        }

        $name = sanitize_text_field((string) ($payload['name'] ?? ''));
        $description = sanitize_textarea_field((string) ($payload['description'] ?? ''));
        $status = sanitize_text_field((string) ($payload['status'] ?? 'draft'));
        if (!in_array($status, ['draft', 'active'], true)) {
            $status = 'draft';
        }

        $templateKey = sanitize_text_field((string) ($payload['template_key'] ?? ''));
        $actionType = sanitize_text_field((string) ($payload['action_type'] ?? ''));
        if ($actionType === '' && $existingAutomation) {
            $actionType = (string) (($existingAutomation['definition_json']['actions'][0]['type'] ?? 'send_internal_email'));
        }

        $build = AutomationDefinitionBuilder::build($payload, $actionType, $templateKey);
        $definition = $build['definition'];
        $builderMode = $build['builder_mode'];
        $errors = $build['errors'];
        [$definition, $resolutionErrors] = $this->resolveManagedActionConfiguration($definition);
        $errors = array_merge($errors, $resolutionErrors);

        $validation = $status === 'active'
            ? DefinitionValidator::validate($definition)
            : ['valid' => true, 'errors' => []];

        if ($name === '') {
            $validation['valid'] = false;
            $validation['errors'][] = 'Automation name is required.';
        }

        if (!empty($errors)) {
            $validation['valid'] = false;
            $validation['errors'] = array_merge($validation['errors'], $errors);
        }

        if (!$validation['valid']) {
            return $this->error(
                'Automation validation failed.',
                422,
                [
                    'code' => 'automation_validation_failed',
                    'errors' => array_values(array_unique($validation['errors'])),
                ]
            );
        }

        $savedId = AutomationRepository::save([
            'id' => $automationId,
            'name' => $name,
            'description' => $description,
            'status' => $status,
            'builder_mode' => $builderMode,
            'trigger_event' => $definition['trigger']['event'] ?? '',
            'definition_json' => $definition,
        ]);

        $savedAutomation = AutomationRepository::find($savedId);
        $runs = $savedAutomation ? AutomationRunRepository::getRecentForAutomation($savedId) : [];
        (new AutomationsLogger())->info($automationId > 0 ? 'Automation updated' : 'Automation created', [
            'automation_id' => $savedId,
            'automation_name' => $name,
            'status' => $status,
            'trigger_event' => (string) ($definition['trigger']['event'] ?? ''),
            'action_type' => (string) ($definition['actions'][0]['type'] ?? ''),
        ]);

        return $this->success(
            AutomationApiSerializer::detail($savedAutomation ?: [], $runs),
            [],
            $automationId > 0 ? 200 : 201
        );
    }

    private function resolveManagedActionConfiguration(array $definition): array
    {
        $errors = [];

        foreach ((array) ($definition['actions'] ?? []) as $index => $action) {
            if (($action['type'] ?? '') !== 'send_google_ads_conversion') {
                continue;
            }

            $config = is_array($action['config'] ?? null) ? $action['config'] : [];
            $connectionId = absint($config['connection_id'] ?? 0);
            $stageTo = $this->getTargetStageFromDefinition($definition);
            $conversionActionId = trim((string) ($config['conversion_action_id'] ?? ''));
            $conversionActionName = trim((string) ($config['conversion_action_name'] ?? ''));

            if ($connectionId <= 0 || $stageTo === '') {
                continue;
            }

            $leadUploadStatus = GoogleAdsLeadUploadStatusService::forConnectionId($connectionId, true);
            if (empty($leadUploadStatus['is_ready'])) {
                $errors[] = GoogleAdsLeadUploadStatusService::buildAutomationBlockMessage($leadUploadStatus);
                continue;
            }

            try {
                $resolved = GoogleAdsConversionActionResolver::ensureForStage(
                    $connectionId,
                    $stageTo,
                    $conversionActionId,
                    $conversionActionName
                );

                $definition['actions'][$index]['config']['conversion_action_id'] = $resolved['id'];
                $definition['actions'][$index]['config']['conversion_action_name'] = $resolved['name'];
            } catch (\Throwable $e) {
                $errors[] = 'Could not prepare the Google Ads conversion action. ' . $e->getMessage();
            }
        }

        return [$definition, $errors];
    }

    private function getTargetStageFromDefinition(array $definition): string
    {
        foreach ((array) ($definition['conditions'] ?? []) as $condition) {
            if (
                ($condition['field'] ?? '') === 'context.stage.to' &&
                ($condition['operator'] ?? '') === 'equals'
            ) {
                return sanitize_text_field((string) ($condition['value'] ?? ''));
            }
        }

        return '';
    }

    private function deleteAutomation(int $automationId)
    {
        if ($automationId <= 0) {
            return $this->error('Automation not found.', 404, 'automation_not_found');
        }

        $automation = AutomationRepository::find($automationId);
        if (!$automation) {
            return $this->error('Automation not found.', 404, 'automation_not_found');
        }

        AutomationRepository::delete($automationId);
        (new AutomationsLogger())->warning('Automation deleted', [
            'automation_id' => $automationId,
            'automation_name' => (string) ($automation['name'] ?? ''),
            'status' => 'deleted',
            'trigger_event' => (string) ($automation['trigger_event'] ?? ''),
        ]);

        return $this->success([
            'deleted' => true,
            'automationId' => $automationId,
        ]);
    }
}
