<?php

namespace MintyPHP\Tests\Architecture;

use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

/**
 * GR-CORE-012: POST handlers that mutate state MUST redirect (PRG pattern)
 * or return JSON. API/data endpoints and multi-step wizards are exempt.
 */
class PostRedirectGetContractTest extends TestCase
{
    use ProjectFileAssertionSupport;

    /** Patterns for endpoints exempt from PRG (JSON, data, wizards). */
    private const PRG_EXEMPT_PATTERNS = [
        '#/api/v1/#',
        '#/data\(\)\.php$#',
        '#/ingest\(\)\.php$#',
        '#/imports/index\(\)\.php$#', // multi-step import wizard renders stages inline
    ];

    public function testAllPostHandlersUseRedirectAfterMutation(): void
    {
        $pagesDir = $this->projectRootPath() . '/pages';
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pagesDir));

        $missing = [];

        /** @var \SplFileInfo $file */
        foreach ($iterator as $file) {
            if (!$file->isFile() || $file->getExtension() !== 'php') {
                continue;
            }

            $relativePath = 'pages/' . ltrim(str_replace($pagesDir, '', $file->getPathname()), '/');

            if ($this->isPrgExempt($relativePath)) {
                continue;
            }

            $content = (string) file_get_contents($file->getPathname());

            if (!$this->handlesPostData($content)) {
                continue;
            }

            // Router::redirect (PRG) or Router::json (AJAX) are both valid responses.
            if (!str_contains($content, 'Router::redirect') && !str_contains($content, 'Router::json')) {
                $missing[] = $relativePath;
            }
        }

        sort($missing);

        $this->assertSame(
            [],
            $missing,
            "POST handlers missing Router::redirect() — PRG pattern required (GR-CORE-012):\n" . implode("\n", $missing)
        );
    }

    private function isPrgExempt(string $path): bool
    {
        foreach (self::PRG_EXEMPT_PATTERNS as $pattern) {
            if (preg_match($pattern, $path)) {
                return true;
            }
        }

        return false;
    }

    private function handlesPostData(string $content): bool
    {
        return str_contains($content, "isMethod('POST')")
            || str_contains($content, 'hasBody(')
            || str_contains($content, 'bodyAll()')
            || preg_match('/->body\(/', $content) === 1;
    }
}
