<?php

namespace app\controller\Api;

use app\service\ArticleImportService;
use JsonException;
use support\Request;
use support\Response;
use Webman\Http\UploadFile;
use Throwable;

class ArticleImportController
{
    public function import(Request $request): Response
    {
        try {
            $payload = $this->payload($request);
        } catch (JsonException $exception) {
            return $this->jsonResponse([
                'code' => 400,
                'message' => 'Invalid JSON body.',
                'errors' => ['body' => $exception->getMessage()],
            ], 400);
        }

        $service = new ArticleImportService();
        $result = $service->import($payload);

        if (!$result['ok']) {
            return $this->jsonResponse([
                'code' => 422,
                'message' => 'Archive import validation failed.',
                'errors' => $result['errors'],
            ], 422);
        }

        try {
            $service->persistSnapshot($result['data']);
            (new \app\service\ArchiveRepository())->saveImport($result['data']);
            if (($result['data']['queue']['needs_ai_metadata'] ?? false) === true && (new \app\service\ArchiveMetadataEnrichmentService())->isEnabled()) {
                $archiveUid = $result['data']['archive']['archive_uid'];
                (new \app\service\ArchiveRepository())->markAiMetadataStatus($archiveUid, 'queued');

                try {
                    (new \app\service\AiMetadataQueue())->push($archiveUid);
                    $result['data']['queue']['ai_metadata_enqueued'] = true;
                } catch (Throwable $queueException) {
                    (new \app\service\ArchiveRepository())->markAiMetadataStatus($archiveUid, 'failed_retryable', $queueException->getMessage());
                    $result['data']['queue']['ai_metadata_enqueue_error'] = $queueException->getMessage();
                }
            } elseif (($result['data']['queue']['needs_ai_metadata'] ?? false) === true) {
                (new \app\service\ArchiveRepository())->markAiMetadataStatus(
                    $result['data']['archive']['archive_uid'],
                    'disabled',
                    'AI metadata enrichment is not enabled.'
                );
            }
        } catch (Throwable $exception) {
            return $this->jsonResponse([
                'code' => 500,
                'message' => 'Archive import data could not be saved.',
                'errors' => ['storage' => $exception->getMessage()],
            ], 500);
        }

        return $this->jsonResponse([
            'code' => 0,
            'message' => 'Archive imported.',
            'data' => $result['data'],
        ], 201);
    }

    /**
     * @throws JsonException
     */
    private function payload(Request $request): array
    {
        $payload = array_merge($request->get(), $request->post());
        $file = $request->file('file');

        if ($file instanceof UploadFile) {
            if (!$file->isValid()) {
                return $payload + ['file_error' => $file->getUploadErrorCode()];
            }

            $payload['content'] = file_get_contents($file->getPathname()) ?: '';
            $payload['source'] = $payload['source'] ?? $file->getUploadName();
            $payload['title'] = $payload['title'] ?? pathinfo($file->getUploadName() ?? '', PATHINFO_FILENAME);
            $payload['metadata'] = $this->metadata($payload['metadata'] ?? null);
            return $payload;
        }

        $rawBody = trim($request->rawBody());
        if ($rawBody === '') {
            $payload['metadata'] = $this->metadata($payload['metadata'] ?? null);
            return $payload;
        }

        if ($this->isJsonRequest($request)) {
            $jsonPayload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
            if (!is_array($jsonPayload)) {
                return [];
            }

            $jsonPayload['metadata'] = $this->metadata($jsonPayload['metadata'] ?? null);
            return $jsonPayload;
        }

        $payload['content'] = $rawBody;
        $payload['source'] = $payload['source'] ?? 'raw-markdown';
        $payload['metadata'] = $this->metadata($payload['metadata'] ?? null);
        return $payload;
    }

    private function isJsonRequest(Request $request): bool
    {
        $contentType = strtolower($request->header('content-type', ''));
        return str_contains($contentType, 'application/json') || str_contains($contentType, '+json');
    }

    private function metadata(mixed $metadata): array
    {
        if (is_array($metadata)) {
            return $metadata;
        }

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

        try {
            $decoded = json_decode($metadata, true, 512, JSON_THROW_ON_ERROR);
            return is_array($decoded) ? $decoded : [];
        } catch (JsonException) {
            return [];
        }
    }

    private function jsonResponse(array $data, int $status): Response
    {
        return response(
            json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR),
            $status,
            ['Content-Type' => 'application/json']
        );
    }
}
