<?php

namespace Tests\Feature;

use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Test\CIUnitTestCase;
use Firebase\JWT\JWT;

class ContactControllerTest extends CIUnitTestCase
{
    use FeatureTestTrait;

    protected $token;

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

        // Generate JWT Token
        $key = getenv('JWT_SECRET') ?: 'my-secret-key';
        $payload = [
            'iss' => 'localhost',
            'aud' => 'localhost',
            'iat' => time(),
            'nbf' => time(),
            'exp' => time() + 3600,
            'uid' => 1,
            'email' => 'admin@admin.com'
        ];
        $this->token = JWT::encode($payload, $key, 'HS256');
    }

    protected function callProtected($method, $path, $params = [])
    {
        return $this->withHeaders(['Cookie' => 'token=' . $this->token])
                    ->call($method, $path, $params);
    }

    private function createContact(array $overrides = []): int
    {
        $payload = array_merge([
            'NameFirst' => 'PartialContact',
            'NameLast' => 'Tester',
            'Specialty' => 'GP',
            'Occupation' => 'MD',
        ], $overrides);

        $result = $this->withHeaders(['Cookie' => 'token=' . $this->token])
                       ->withBody(json_encode($payload))
                       ->call('post', 'api/contact');

        $result->assertStatus(201);
        $data = json_decode($result->getJSON(), true);

        return $data['data']['ContactID'] ?? 0;
    }

    public function testIndexReturnsSuccess()
    {
        $result = $this->callProtected('get', 'api/contact');

        $result->assertStatus(200);
        $json = $result->getJSON();
        $data = json_decode($json, true);

        $this->assertEquals('success', $data['status']);
        $this->assertIsArray($data['data']);
    }

    public function testShowReturnsDataIfFound()
    {
        $indexResult = $this->callProtected('get', 'api/contact');
        $indexData = json_decode($indexResult->getJSON(), true);
        
        if (empty($indexData['data'])) {
            $this->markTestSkipped('No contacts found in database to test show.');
        }

        $id = $indexData['data'][0]['ContactID'];
        $result = $this->callProtected('get', "api/contact/$id");

        $result->assertStatus(200);
        $json = $result->getJSON();
        $data = json_decode($json, true);

        $this->assertEquals('success', $data['status']);
        $this->assertIsArray($data['data']);
        $this->assertEquals($id, $data['data']['ContactID']);
    }

    public function testCreateContact()
    {
        $contactData = [
            'NameFirst' => 'TestContact' . time(),
            'NameLast' => 'LastName',
            'Specialty' => 'GP',
            'Occupation' => 'MD'
        ];

        $result = $this->withHeaders(['Cookie' => 'token=' . $this->token])
                       ->withBody(json_encode($contactData))
                       ->call('post', 'api/contact');

        $result->assertStatus(201);
        $json = $result->getJSON();
        $data = json_decode($json, true);

        $this->assertEquals('success', $data['status']);
        $this->assertIsArray($data['data']);
        $this->assertEquals('success', $data['data']['status']);
        $this->assertIsInt($data['data']['ContactID']);
    }

    public function testCreateContactWithDetails()
    {
        $contactData = [
            'NameFirst' => 'TestContact' . time(),
            'NameLast' => 'LastName',
            'Initial' => 'TC',
            'Details' => [
                [
                    'SiteID' => '1',
                    'ContactCode' => 'CODE1',
                    'ContactEmail' => 'code1@example.com',
                    'OccupationID' => '1',
                    'JobTitle' => 'Doctor',
                    'Department' => 'General',
                ],
                [
                    'SiteID' => '2',
                    'ContactCode' => 'CODE2',
                    'ContactEmail' => 'code2@example.com',
                    'OccupationID' => '2',
                    'JobTitle' => 'Specialist',
                    'Department' => 'Laboratory',
                ],
            ],
        ];

        $result = $this->withHeaders(['Cookie' => 'token=' . $this->token])
                       ->withBody(json_encode($contactData))
                       ->call('post', 'api/contact');

        $result->assertStatus(201);
        $data = json_decode($result->getJSON(), true);
        $contactId = $data['data']['ContactID'] ?? null;

        $this->assertIsInt($contactId);

        $show = $this->callProtected('get', 'api/contact/' . $contactId);
        $show->assertStatus(200);
        $showData = json_decode($show->getJSON(), true)['data'];

        $this->assertCount(2, $showData['Details']);
        $this->assertEqualsCanonicalizing(['1', '2'], array_column($showData['Details'], 'SiteID'));
    }

    public function testPartialUpdateContactWithSingleField()
    {
        $contactId = $this->createContact(['NameFirst' => 'Original']);

        $patch = $this->withHeaders(['Cookie' => 'token=' . $this->token])
                      ->withBodyFormat('json')
                      ->call('patch', 'api/contact/' . $contactId, [
            'NameFirst' => 'Patched'
        ]);

        $patch->assertStatus(200);
        $response = json_decode($patch->getJSON(), true);
        $this->assertEquals('success', $response['status']);

        $show = $this->callProtected('get', 'api/contact/' . $contactId);
        $show->assertStatus(200);
        $showData = json_decode($show->getJSON(), true)['data'];
        $this->assertEquals('Patched', $showData['NameFirst']);
        $this->assertEquals('Tester', $showData['NameLast']);
    }
}
