<?php

namespace {
    if (!function_exists('view')) {
        function view($name, array $data = [], $options = [])
        {
            return ['view' => $name, 'data' => $data, 'options' => $options];
        }
    }

    if (!function_exists('local_date')) {
        function local_date($timestamp, $format)
        {
            if ($timestamp instanceof \DateTimeInterface) {
                return $timestamp->format($format);
            }
            if (is_numeric($timestamp)) {
                return date($format, (int) $timestamp);
            }
            return date($format);
        }
    }
}

namespace Tests\App\Controllers\View {

    use App\Controllers\View\AdministratorController;
use App\Models\UserModel;
use CodeIgniter\HTTP\RedirectResponse;
    use CodeIgniter\Test\CIUnitTestCase;
    use Config\Services;

    class DummyPostRequest
{
    public function __construct(private array $post = [])
    {
    }

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

    class FakeRenderer
    {
        public array $lastData = [];
        public string $lastName = '';

        public function setData(array $data, string $type = 'raw')
        {
            $this->lastData = $data;
            return $this;
        }

        public function render(string $name, array $options = [], bool $saveData = false)
        {
            $this->lastName = $name;
            return 'fake-render';
        }
    }

    class FakeAttendanceModel
    {
        public function __construct(private array $existing = [])
        {
        }

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

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

        public function findAll()
        {
            return $this->existing;
        }

        public function upsertOne(...$args)
        {
            return true;
        }
    }

    class TestableAdministratorController extends AdministratorController
    {
        public function __construct()
        {
            // Skip expensive parent constructor to avoid real DB/models.
        }

    public function setUserModel(UserModel $model): self
    {
        $this->userModel = $model;
        return $this;
    }

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

        public function setSemester(string $semester): self
        {
            $this->semester = $semester;
            return $this;
        }

        public function setSchoolYear(string $schoolYear): self
        {
            $this->schoolYear = $schoolYear;
            return $this;
        }

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

    class AdministratorControllerTest extends CIUnitTestCase
    {
        private TestableAdministratorController $controller;
        private FakeRenderer $renderer;

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

            Services::resetSingle('session');
            helper('date');
            session()->start();

            $this->controller = new TestableAdministratorController();
            $this->controller->setSemester('Fall')->setSchoolYear('2024-2025');
            $this->renderer = new FakeRenderer();
            Services::injectMock('renderer', $this->renderer);
        }

    protected function tearDown(): void
    {
        Services::resetSingle('renderer');
        session()->destroy();
        parent::tearDown();
    }

    public function testAbsenceFormRedirectsWhenNotLoggedIn()
    {
        session()->remove('user_id');

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

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

    public function testAbsenceFormBuildsViewWithAttendance()
    {
        session()->set('user_id', 7);

        $userModel = $this->createMock(UserModel::class);
        $userModel->method('find')->with(7)->willReturn([
            'firstname' => 'Alex',
            'lastname' => 'Admin',
        ]);

        $attendance = new FakeAttendanceModel([
            ['date' => '2024-12-01'],
        ]);

        $this->controller->setUserModel($userModel)->setStaffAttendanceModel($attendance);

        $result = $this->controller->absenceFormAdmin();

        if (is_array($result)) {
            $this->assertSame('administrator/absence_vacation', $result['view']);
            $data = $result['data'];
        } else {
            $this->assertSame('fake-render', $result);
            $this->assertSame('administrator/absence_vacation', $this->renderer->lastName);
            $data = $this->renderer->lastData;
        }
        $this->assertSame('Alex Admin', $data['admin_name']);
        $this->assertSame('Fall', $data['semester']);
        $this->assertSame('2024-2025', $data['schoolYear']);
        $this->assertSame([['date' => '2024-12-01']], $data['existing']);
        $this->assertIsArray($data['availableDates']);
    }

    public function testSubmitAbsenceRejectsMissingReason()
    {
        session()->set('user_id', 9);

        $req = new DummyPostRequest([
            'dates' => ['2024-12-01'],
            'reason_type' => '',
            'reason' => '',
        ]);

        $this->controller->setRequest($req);

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

        $this->assertInstanceOf(RedirectResponse::class, $response);
        $this->assertStringContainsString('/administrator/absence', $response->getHeaderLine('Location') ?: '');
        $this->assertSame('Reason is required.', session()->getFlashdata('message'));
    }

    public function testSubmitAbsenceSavesAndRedirects()
    {
        session()->set('user_id', 10);

        $userModel = $this->createMock(UserModel::class);
        $userModel->method('getUserRole')->with(10)->willReturn('administrator');
        $userModel->method('find')->with(10)->willReturn([
            'firstname' => 'Sam',
            'lastname' => 'Admin',
            'email' => 'sam@school.test',
        ]);

        $attendance = new FakeAttendanceModel();
        $this->controller->setUserModel($userModel)->setStaffAttendanceModel($attendance);

        $method = new \ReflectionMethod($this->controller, 'allowedAbsenceDates');
        $method->setAccessible(true);
        $allowed = $method->invoke($this->controller);

        if (empty($allowed)) {
            $this->markTestSkipped('No allowed absence dates are currently available.');
        }

        $date = $allowed[0];

        $req = new DummyPostRequest([
            'dates' => [$date],
            'reason_type' => 'Personal',
            'reason' => 'Conference',
        ]);
        $this->controller->setRequest($req);

        $emailService = $this->createMock(\App\Services\EmailService::class);
        $emailService->method('send')->willReturn(true);
        Services::injectMock('emailService', $emailService);

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

        $this->assertInstanceOf(RedirectResponse::class, $response);
        $this->assertStringContainsString('/administrator/absence', $response->getHeaderLine('Location') ?: '');
        $this->assertSame('success', session()->getFlashdata('status'));
        $this->assertStringContainsString('saved', (string) session()->getFlashdata('message'));
    }
}
}
