<?php

namespace App\Controllers\View {
    if (!function_exists(__NAMESPACE__ . '\view')) {
        function view($name, array $data = [], $options = [])
        {
            return ['view' => $name, 'data' => $data, 'options' => $options];
        }
    }
}

namespace Tests\App\Controllers\View {

use App\Controllers\View\PaymentController;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\Test\CIUnitTestCase;

class PaymentRequestStub
{
    public function __construct(
        private string $method = 'get',
        private array $post = [],
        private $file = null
    ) {
    }

    public function getMethod(): string
    {
        return $this->method;
    }

    public function getPost(?string $key = null)
    {
        if ($key === null) {
            return $this->post;
        }

        return $this->post[$key] ?? null;
    }

    public function getFile(string $name)
    {
        return $name === 'proof' ? $this->file : null;
    }
}

class ManualPaymentModelSpy
{
    public array $inserted = [];

    public function insert(array $data)
    {
        $this->inserted[] = $data;
        return true;
    }
}

class AttachmentServiceStub
{
    public function __construct(private ?string $path = null)
    {
    }

    public function saveUploadedFile($file, string $subdir): ?string
    {
        return $this->path;
    }
}

class TestablePaymentController extends PaymentController
{
    public function __construct()
    {
    }

    public function setRequestObject($request): self
    {
        $this->request = $request;
        return $this;
    }

    public function setManualPaymentModel($model): self
    {
        $this->manualPaymentModel = $model;
        return $this;
    }

    public function setAttachmentService($service): self
    {
        $this->financialAttachmentService = $service;
        return $this;
    }
}

class PaymentControllerRegressionTest extends CIUnitTestCase
{
    public function testRedirectPageSendsUsersBackToInvoicePaymentWithInfoMessage(): void
    {
        $controller = new TestablePaymentController();

        $response = $controller->redirectPage();

        $this->assertInstanceOf(RedirectResponse::class, $response);
        $this->assertStringContainsString('parent/invoice_payment', $response->getHeaderLine('Location'));
    }

    public function testManualGetReturnsManualPaymentView(): void
    {
        $controller = (new TestablePaymentController())
            ->setRequestObject(new PaymentRequestStub('get'));

        $result = $controller->manual();

        $this->assertSame('payment/manual_payment', $result['view']);
    }

    public function testManualPostStoresProofPathFromAttachmentService(): void
    {
        $model = new ManualPaymentModelSpy();
        $controller = (new TestablePaymentController())
            ->setManualPaymentModel($model)
            ->setAttachmentService(new AttachmentServiceStub('proofs/check-123.pdf'))
            ->setRequestObject(new PaymentRequestStub('post', [
                'invoice_number' => 'INV-001',
                'amount' => '125.00',
                'payment_method' => 'check',
                'reference' => 'CHK123',
            ], new \stdClass()));

        $response = $controller->manual();

        $this->assertInstanceOf(RedirectResponse::class, $response);
        $this->assertCount(1, $model->inserted);
        $this->assertSame('proofs/check-123.pdf', $model->inserted[0]['proof_path']);
        $this->assertSame('INV-001', $model->inserted[0]['invoice_number']);
    }
}
}
