<?php

namespace Tests\App\Controllers\Api;

use App\Controllers\Api\BroadcastEmailController;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockIncomingRequest;
use Config\App;

class FakeBroadcastRequest extends MockIncomingRequest
{
    public function __construct(private readonly ?array $json = null)
    {
        parent::__construct(config(App::class), new URI('https://test.alrahmaisgl.org'), 'php://input', new UserAgent());
    }

    public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0): ?array
    {
        return $this->json;
    }
}

class StubBroadcastModel
{
    public array $inserted = [];

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

class StubUserModel
{
    public function __construct(private readonly array $parents = [])
    {
    }

    public function select($columns)
    {
        return $this;
    }

    public function join(...$args)
    {
        return $this;
    }

    public function where(...$args)
    {
        return $this;
    }

    public function findAll(): array
    {
        return $this->parents;
    }
}

class TestableBroadcastEmailController extends BroadcastEmailController
{
    public bool $validationResult = true;
    public array $validationErrors = [];
    public $validator;

    public function __construct()
    {
        // keep the parent constructor from running to avoid real models
    }

    public function setBroadcastModel(StubBroadcastModel $model): void
    {
        $this->broadcastModel = $model;
    }

    public function setUserModel(StubUserModel $model): void
    {
        $this->userModel = $model;
    }

    public function setValidationResult(bool $result, array $errors = []): void
    {
        $this->validationResult = $result;
        $this->validationErrors = $errors;
    }

    protected function validate($rules, array $messages = []): bool
    {
        $this->validator = new class($this->validationErrors) {
            public function __construct(private readonly array $errors)
            {
            }

            public function getErrors(): array
            {
                return $this->errors;
            }
        };

        return $this->validationResult;
    }

    protected function respondSuccess($data = null, string $message = 'Success', int $code = ResponseInterface::HTTP_OK)
    {
        return ['status' => true, 'message' => $message, 'data' => $data, 'code' => $code];
    }

    protected function respondValidationError(array $errors, string $message = 'Validation failed')
    {
        return ['status' => false, 'message' => $message, 'errors' => $errors, 'code' => ResponseInterface::HTTP_UNPROCESSABLE_ENTITY];
    }
}

class BroadcastEmailControllerTest extends CIUnitTestCase
{
    private TestableBroadcastEmailController $controller;
    private StubBroadcastModel $broadcastModel;

    protected function setUp(): void
    {
        parent::setUp();

        $this->controller = new TestableBroadcastEmailController();
        $this->broadcastModel = new StubBroadcastModel();
        $this->controller->setBroadcastModel($this->broadcastModel);
    }

    public function testSendValidationFails(): void
    {
        $this->controller->setValidationResult(false, ['subject' => 'required']);
        $this->controller->setRequest(new FakeBroadcastRequest(['subject' => '', 'body' => '', 'recipients' => []]));

        $response = $this->controller->send();

        $this->assertSame(ResponseInterface::HTTP_UNPROCESSABLE_ENTITY, $response['code']);
        $this->assertSame('Validation failed', $response['message']);
        $this->assertArrayHasKey('subject', $response['errors']);
    }

    public function testSendStoresSentAndFailedRecipients(): void
    {
        $requestData = [
            'subject' => 'Weekly Update',
            'body' => 'Hello parents',
            'recipients' => ['parent1@example.com', 'bad-email'],
        ];
        $this->controller->setRequest(new FakeBroadcastRequest($requestData));

        $response = $this->controller->send();

        $this->assertSame(ResponseInterface::HTTP_OK, $response['code']);
        $this->assertSame('Broadcast email sent successfully', $response['message']);
        $this->assertSame(['parent1@example.com'], $response['data']['sent']);
        $this->assertSame(['bad-email'], $response['data']['failed']);
        $this->assertCount(1, $this->broadcastModel->inserted);
        $data = $this->broadcastModel->inserted[0];
        $this->assertSame('Weekly Update', $data['subject']);
        $this->assertSame('Hello parents', $data['body']);
        $this->assertSame(1, $data['total_sent']);
        $this->assertArrayHasKey('created_at', $data);
    }

    public function testParentsReturnsParentList(): void
    {
        $parents = [
            ['id' => 10, 'firstname' => 'Test', 'lastname' => 'Parent', 'email' => 'test@parent.com'],
        ];
        $this->controller->setUserModel(new StubUserModel($parents));

        $response = $this->controller->parents();

        $this->assertSame(ResponseInterface::HTTP_OK, $response['code']);
        $this->assertSame('Parent list retrieved successfully', $response['message']);
        $this->assertSame($parents, $response['data']);
    }
}
