<?php

namespace App\Services\Api\Actions;

use App\Models\Environments\Data;
use App\Models\Environments\Environment;
use App\Models\Environments\Plugin;
use App\Models\Environments\Type;
use App\Services\Api\HostNormalizer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class SyncAction implements ActionInterface
{
    public function execute(Request $request, array $payload): array
    {
        $environmentData = $payload['environment'] ?? $payload['site'] ?? [];
        $projectId = $payload['projectid'] ?? null;
        $pluginsList = $payload['data']['plugins'] ?? [];

        /** @var Environment $environment */
        $environment = $request->input('_environment');

        if (!$environment) {
            throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException('Environment not found for this host');
        }

        $processed = 0;
        $errors = [];

        DB::transaction(function () use ($request, $environment, $environmentData, $projectId, $pluginsList, &$processed, &$errors) {
            $environment = Environment::where('id', $environment->id)->lockForUpdate()->first();
            if (!$environment) {
                throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException('Environment not found');
            }

            $normalizedHost = $request->input('_normalized_host');
            if ($normalizedHost === null) {
                $normalizedHost = HostNormalizer::normalize($request->input('host', ''));
            }

            $type = null;
            if (!empty($environmentData['type'])) {
                $type = Type::where('shortname', $environmentData['type'])->first();
            }

            $environmentAttributes = [
                'version' => $environmentData['version'] ?? $environment->version,
                'env' => $environmentData['env'] ?? $environment->env,
                'lastversion' => $environmentData['lastversion'] ?? $environment->lastversion,
                'lastminor' => $environmentData['lastminor'] ?? $environment->lastminor,
                'moodletoken' => $environmentData['token'] ?? $environment->moodletoken,
                'type_id' => $type?->id ?? $environment->type_id,
                'key' => $projectId ?? $environment->key,
                'refresh_at' => now(),
            ];

            if ($normalizedHost !== '') {
                $environmentAttributes['domain'] = $normalizedHost;
            }

            $environment->update($environmentAttributes);

            $dataAttributes = [];
            if (array_key_exists('release', $environmentData)) {
                $dataAttributes['moodlerelease'] = $environmentData['release'];
            }
            if (array_key_exists('availableupdatesfetch', $environmentData)) {
                $dataAttributes['availableupdatesfetch'] = (string) $environmentData['availableupdatesfetch'];
            }
            if ($dataAttributes !== []) {
                Data::updateOrCreate(
                    ['environment_id' => $environment->id],
                    $dataAttributes
                );
            }

            Plugin::where('environment_id', $environment->id)->forceDelete();

            foreach ($pluginsList as $pluginData) {
                try {
                    $this->insertPlugin($environment, $pluginData);
                    $processed++;
                } catch (\Exception $e) {
                    $errors[] = [
                        'plugin' => $pluginData['name'] ?? $pluginData['component'] ?? 'unknown',
                        'error' => $e->getMessage(),
                    ];
                }
            }
        });

        $environment->refresh();
        $environment->load('type');

        return [
            'id' => $environment->id,
            'name' => $environment->name,
            'domain' => $environment->domain,
            'version' => $environment->version,
            'env' => $environment->env,
            'type' => $environment->type?->shortname,
            'lastversion' => $environment->lastversion,
            'lastminor' => $environment->lastminor,
            'active' => $environment->active,
            'has_support' => $environment->has_support,
            'plugins_count' => $processed,
            'processed' => $processed,
            'total' => count($pluginsList),
            'errors' => $errors,
        ];
    }

    private function insertPlugin(Environment $environment, array $pluginData): void
    {
        $name = $pluginData['name'] ?? '';
        $component = $pluginData['component'] ?? '';

        if ($name === '' && $component === '') {
            throw new \InvalidArgumentException('El plugin debe tener al menos name o component');
        }

        $versionRequires = $pluginData['versionrequires'] ?? 0;
        $versiondisk = $pluginData['versiondisk'] ?? $pluginData['version'] ?? '0';
        $versiondb = $pluginData['versiondb'] ?? $pluginData['version'] ?? '0';
        $type = $pluginData['type'] ?? '';

        $dependencies = $pluginData['dependencies'] ?? null;
        $availableupdates = $pluginData['availableupdates'] ?? null;

        Plugin::create([
            'environment_id' => $environment->id,
            'name' => $name !== '' ? $name : $component,
            'component' => $component !== '' ? $component : $name,
            'type' => $type,
            'versiondisk' => (string) $versiondisk,
            'versiondb' => (string) $versiondb,
            'versionrequires' => (int) $versionRequires,
            'pluginsupported' => $pluginData['pluginsupported'] ?? null,
            'pluginincompatible' => $pluginData['pluginincompatible'] ?? null,
            'release' => $pluginData['release'] ?? null,
            'has_dependencies' => !empty($dependencies),
            'dependencies' => $dependencies,
            'has_updates' => !empty($availableupdates),
            'availableupdates' => $availableupdates,
        ]);
    }
}
