<?php

namespace GriffinForms\Includes\Ai\PromptRegistry\Handlers\Row;

class RowPromptHelper
{
    public function isPageRewritePrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        return $this->containsAnyToken($tokens, ['rewrite', 'improve', 'update', 'change', 'edit', 'refine', 'polish'])
            && $this->containsAnyToken($tokens, ['heading', 'title', 'description', 'text', 'copy'])
            && $this->containsAnyToken($tokens, ['page', 'pages', 'step', 'steps']);
    }

    public function isAllPageHeadingPrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        return $this->containsAnyToken($tokens, ['all', 'every', 'each', 'bulk'])
            && $this->containsAnyToken($tokens, ['heading', 'headings', 'title', 'titles'])
            && $this->containsAnyToken($tokens, ['rewrite', 'improve', 'update', 'change', 'edit', 'refine', 'polish', 'add'])
            && $this->containsAnyToken($tokens, ['page', 'pages', 'step', 'steps']);
    }

    public function isAllPageDescriptionPrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        return $this->containsAnyToken($tokens, ['all', 'every', 'each', 'bulk'])
            && $this->containsAnyToken($tokens, ['description', 'descriptions', 'copy', 'text'])
            && $this->containsAnyToken($tokens, ['rewrite', 'improve', 'update', 'change', 'edit', 'refine', 'polish', 'add'])
            && $this->containsAnyToken($tokens, ['page', 'pages', 'step', 'steps']);
    }

    public function isRowInsertRequest(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        if ($this->containsAnyToken($tokens, ['heading', 'title', 'description', 'descriptions', 'text', 'copy'])) {
            return false;
        }

        return $this->containsAnyToken($tokens, ['add', 'insert', 'create', 'new'])
            && $this->containsAnyToken($tokens, ['row', 'section', 'fila', 'ligne', 'zeile', 'riga']);
    }

    public function isRowMoveRequest(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        $has_move_verb = $this->containsAnyToken($tokens, ['move', 'shift', 'reorder']);
        $has_direction = $this->containsAnyToken($tokens, ['up', 'down', 'before', 'after', 'above', 'below', 'previous', 'next', 'earlier', 'later', 'top', 'bottom']);
        $has_ordinal_position = $this->extractRequestedRowPosition($normalized_prompt) !== null;
        $has_row_noun = $this->containsAnyToken($tokens, ['row', 'section', 'fila', 'ligne', 'zeile', 'riga']);

        return $has_move_verb && ($has_direction || $has_ordinal_position || $has_row_noun);
    }

    public function isRowTargetingPrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        $has_action = $this->containsAnyToken($tokens, ['move', 'delete', 'remove', 'clear', 'heading', 'description', 'title']);
        $has_row_noun = $this->containsAnyToken($tokens, ['row', 'section', 'fila', 'ligne', 'zeile', 'riga']);

        return $has_action && $has_row_noun;
    }

    public function isRowRewritePrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        return $this->containsAnyToken($tokens, ['rewrite', 'rewrite', 'improve', 'update', 'change', 'edit', 'refine', 'polish'])
            && $this->containsAnyToken($tokens, ['heading', 'title', 'description', 'text', 'copy']);
    }

    public function isAllRowHeadingPrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        $has_bulk = $this->containsAnyToken($tokens, ['all', 'every', 'each', 'bulk']);
        $has_heading = $this->containsAnyToken($tokens, ['heading', 'title']);
        $has_action = $this->containsAnyToken($tokens, ['rewrite', 'improve', 'update', 'change', 'edit', 'refine', 'polish', 'add']);
        return $has_bulk && $has_heading && $has_action;
    }

    public function isAllRowDescriptionPrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        $has_bulk = $this->containsAnyToken($tokens, ['all', 'every', 'each', 'bulk']);
        $has_description = $this->containsAnyToken($tokens, ['description', 'descriptions', 'copy', 'text']);
        $has_action = $this->containsAnyToken($tokens, ['rewrite', 'improve', 'update', 'change', 'edit', 'refine', 'polish', 'add']);
        return $has_bulk && $has_description && $has_action;
    }

    public function isRowDeletePrompt(string $normalized_prompt): bool
    {
        $tokens = $this->tokenizePrompt($normalized_prompt);
        return $this->containsAnyToken($tokens, ['delete', 'remove', 'clear']);
    }

    public function extractRequestedRowPosition(string $prompt): ?array
    {
        $tokens = $this->tokenizePrompt($prompt);
        $position_tokens = array_values(array_intersect($tokens, ['top', 'bottom', 'last', 'end', 'final']));
        if (!empty($position_tokens)) {
            $edge = in_array($position_tokens[0], ['bottom', 'last', 'end', 'final'], true) ? 'bottom' : $position_tokens[0];
            return [
                'type' => 'edge',
                'value' => $edge,
            ];
        }

        for ($i = 0, $count = count($tokens); $i < $count; $i++) {
            $token = $tokens[$i];
            $ordinal = $this->parseOrdinalPositionToken($token);
            if ($ordinal === null) {
                continue;
            }

            $next = $tokens[$i + 1] ?? '';
            $next2 = $tokens[$i + 2] ?? '';
            if (in_array($next, ['position', 'place', 'slot', 'row'], true) || in_array($next2, ['position', 'place', 'slot', 'row'], true)) {
                return [
                    'type' => 'ordinal',
                    'value' => $ordinal,
                ];
            }
        }

        return null;
    }

    public function extractRequestedColumnCount(string $prompt): ?int
    {
        $tokens = $this->tokenizePrompt($prompt);
        $units = ['column', 'columns', 'col', 'cols', 'columnas', 'columna', 'columnas', 'colonnes', 'colonne', 'spalten', 'colonna'];

        for ($i = 0, $count = count($tokens); $i < $count; $i++) {
            $value = $this->parseColumnCountToken($tokens[$i]);
            if ($value === null) {
                continue;
            }

            $next = $tokens[$i + 1] ?? '';
            $next2 = $tokens[$i + 2] ?? '';
            if (in_array($next, $units, true) || in_array($next2, $units, true)) {
                return $value;
            }

            if ($i > 0 && in_array($tokens[$i - 1], ['with', 'having', 'sobre', 'avec', 'mit', 'con'], true) && in_array($next, $units, true)) {
                return $value;
            }
        }

        return null;
    }

    protected function parseColumnCountToken(string $token): ?int
    {
        $token = strtolower(trim($token));
        if ($token === '') {
            return null;
        }

        $phrase_map = [
            'a couple' => 2,
            'couple' => 2,
            'a few' => 3,
            'few' => 3,
            'some' => 3,
            'several' => 4,
        ];
        if (isset($phrase_map[$token])) {
            return $phrase_map[$token];
        }

        if (ctype_digit($token)) {
            return absint($token);
        }

        if (is_numeric($token)) {
            return (int) round((float) $token, 0, PHP_ROUND_HALF_UP);
        }

        $map = [
            'one' => 1, 'single' => 1, 'uno' => 1, 'un' => 1, 'una' => 1, 'eins' => 1, 'ein' => 1,
            'two' => 2, 'double' => 2, 'dos' => 2, 'deux' => 2, 'zwei' => 2, 'due' => 2,
            'three' => 3, 'triple' => 3, 'tres' => 3, 'trois' => 3, 'drei' => 3, 'tre' => 3,
            'four' => 4, 'cuatro' => 4, 'quatre' => 4, 'vier' => 4, 'quattro' => 4,
            'five' => 5, 'cinco' => 5, 'cinq' => 5, 'funf' => 5, 'fuenf' => 5, 'cinque' => 5,
        ];

        return $map[$token] ?? null;
    }

    protected function parseOrdinalPositionToken(string $token): ?int
    {
        $token = strtolower(trim($token));
        if ($token === '') {
            return null;
        }

        if (preg_match('/^(\d+)(?:st|nd|rd|th)?$/', $token, $matches)) {
            return absint($matches[1]);
        }

        $ordinal_map = [
            'first' => 1,
            'second' => 2,
            'third' => 3,
            'fourth' => 4,
            'fifth' => 5,
            'sixth' => 6,
            'seventh' => 7,
            'eighth' => 8,
            'ninth' => 9,
            'tenth' => 10,
        ];

        return $ordinal_map[$token] ?? null;
    }

    protected function tokenizePrompt(string $prompt): array
    {
        $prompt = strtolower(trim($prompt));
        $prompt = str_replace(['-', '_', '/', '\\', ':', ';', ',', '(', ')', '[', ']', '{', '}', '"', "'"], ' ', $prompt);
        $tokens = preg_split('/\s+/', $prompt) ?: [];
        return array_values(array_filter(array_map(static function ($token) {
            return trim($token, " \t\n\r\0\x0B.,!?");
        }, $tokens), static function ($token) {
            return $token !== '';
        }));
    }

    protected function containsAnyToken(array $tokens, array $needles): bool
    {
        $lookup = array_fill_keys($tokens, true);
        foreach ($needles as $needle) {
            if (isset($lookup[$needle])) {
                return true;
            }
        }

        return false;
    }
}
