<?php

/**
 * REST controller for playbook document distillation (admin upload flow).
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Rest;

use LolaCore\Playbooks\Distiller;
use LolaCore\Playbooks\PlaybookDocumentReader;
use LolaCore\Playbooks\PlaybookLoader;
use LolaCore\Playbooks\PlaybookValidator;
use LolaCore\Skills\YamlParser;

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

class PlaybookDistillController
{
    private const NAMESPACE = 'lolacore/v1';
    private const ROUTE     = '/playbooks/distill';

    private PlaybookDocumentReader $reader;
    private Distiller $distiller;
    private PlaybookLoader $loader;

    public function __construct(
        ?PlaybookDocumentReader $reader = null,
        ?Distiller $distiller = null,
        ?PlaybookLoader $parserLoader = null
    ) {
        $this->reader = $reader ?? new PlaybookDocumentReader();

        $parser          = new YamlParser();
        $validator       = new PlaybookValidator();
        $this->loader    = $parserLoader ?? new PlaybookLoader($parser, $validator);
        $this->distiller = $distiller ?? new Distiller($this->loader);
    }

    public function register(): void
    {
        \add_action('rest_api_init', [$this, 'registerRoutes']);
    }

    public function registerRoutes(): void
    {
        \register_rest_route(self::NAMESPACE, self::ROUTE, [
            'methods'             => 'POST',
            'callback'            => [$this, 'handleDistill'],
            'permission_callback' => static function (): bool {
                return \current_user_can('manage_options');
            },
            'args'                => [
                'source_text' => [
                    'required'          => false,
                    'type'              => 'string',
                    'sanitize_callback' => 'wp_unslash',
                ],
                'instructions' => [
                    'required'          => false,
                    'type'              => 'string',
                    'sanitize_callback' => 'wp_unslash',
                ],
            ],
        ]);
    }

    /**
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response|\WP_Error
     */
    public function handleDistill($request)
    {
        try {
            $sourceText   = $this->resolveSourceText($request);
            $instructions = trim((string) $request->get_param('instructions'));

            $draft = $this->distiller->distill($sourceText, $instructions);
            $validation = $this->validateDraft($draft);

            return new \WP_REST_Response([
                'draft'       => $draft,
                'source_text' => $sourceText,
                'warnings'    => $validation['warnings'],
                'valid'       => $validation['valid'],
                'error'       => $validation['error'],
            ], 200);
        } catch (\LolaCore\Playbooks\Exceptions\PlaybookDocumentTooLongException $e) {
            return new \WP_Error(
                'lolacore_playbook_distill_invalid',
                $e->getMessage(),
                array_merge(['status' => 400], $e->toErrorPayload())
            );
        } catch (\InvalidArgumentException $e) {
            return new \WP_Error(
                'lolacore_playbook_distill_invalid',
                $e->getMessage(),
                ['status' => 400]
            );
        } catch (\RuntimeException $e) {
            return new \WP_Error(
                'lolacore_playbook_distill_failed',
                $e->getMessage(),
                ['status' => 502]
            );
        }
    }

    /**
     * @param \WP_REST_Request $request
     */
    private function resolveSourceText($request): string
    {
        $files = $request->get_file_params();
        if (!empty($files['file']['tmp_name'])) {
            return $this->reader->readUploadedFile($files['file']);
        }

        $text = trim((string) $request->get_param('source_text'));
        if ($text === '') {
            throw new \InvalidArgumentException('Upload a document or provide source_text for regeneration.');
        }

        $text = $this->reader->normalize($text);
        return $this->reader->enforceExtractedLimit($text);
    }

    /**
     * @return array{valid:bool,warnings:array<int,string>,error:string}
     */
    private function validateDraft(string $draft): array
    {
        $parsed = $this->loader->parsePlaybookContent(
            $draft,
            \LolaCore\Playbooks\Playbook::ORIGIN_DB,
            'distill://draft'
        );
        if ($parsed instanceof \LolaCore\Playbooks\Exceptions\PlaybookParseError) {
            return [
                'valid'    => false,
                'warnings' => [],
                'error'    => $parsed->getUserMessage(),
            ];
        }
        if ($parsed instanceof \LolaCore\Playbooks\Exceptions\PlaybookValidationError) {
            return [
                'valid'    => false,
                'warnings' => [],
                'error'    => $parsed->getMessage(),
            ];
        }

        return [
            'valid'    => true,
            'warnings' => [],
            'error'    => '',
        ];
    }
}
