<?php

namespace Tests\Feature\Contact;

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

class ContactPatchTest extends CIUnitTestCase
{
    use FeatureTestTrait;

    protected string $token;
    protected string $endpoint = 'api/contact';

    protected function setUp(): void
    {
        parent::setUp();
        $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');
    }

    private function authHeaders(): array
    {
        return ['Cookie' => 'token=' . $this->token];
    }

    private function createContact(array $data = []): array
    {
        $payload = array_merge([
            'NameFirst' => 'Test',
            'NameLast' => 'Contact ' . uniqid(),
            'Specialty' => 'GP',
        ], $data);

        $response = $this->withHeaders($this->authHeaders())
                         ->withBodyFormat('json')
                         ->call('post', $this->endpoint, $payload);

        $response->assertStatus(201);
        $decoded = json_decode($response->getJSON(), true);
        return $decoded['data'];
    }

    public function testPartialUpdateContactSuccess()
    {
        $contact = $this->createContact();
        $id = $contact['ContactID'];

        $patch = $this->withHeaders($this->authHeaders())
                      ->withBodyFormat('json')
                      ->call('patch', "{$this->endpoint}/{$id}", ['NameFirst' => 'Updated']);

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

        $show = $this->withHeaders($this->authHeaders())->call('get', "{$this->endpoint}/{$id}");
        $show->assertStatus(200);
        $showData = json_decode($show->getJSON(), true)['data'];

        $this->assertEquals('Updated', $showData['NameFirst']);
    }

    public function testPartialUpdateContactNotFound()
    {
        $patch = $this->withHeaders($this->authHeaders())
                      ->withBodyFormat('json')
                      ->call('patch', "{$this->endpoint}/999999", ['NameFirst' => 'Updated']);

        $patch->assertStatus(404);
    }

    public function testPartialUpdateContactInvalidId()
    {
        $patch = $this->withHeaders($this->authHeaders())
                      ->withBodyFormat('json')
                      ->call('patch', "{$this->endpoint}/invalid", ['NameFirst' => 'Updated']);

        $patch->assertStatus(400);
    }

    public function testPartialUpdateContactEmptyPayload()
    {
        $contact = $this->createContact();
        $id = $contact['ContactID'];

        $patch = $this->withHeaders($this->authHeaders())
                      ->withBodyFormat('json')
                      ->call('patch', "{$this->endpoint}/{$id}", []);

        $patch->assertStatus(400);
    }

    public function testPartialUpdateContactSingleField()
    {
        $contact = $this->createContact();
        $id = $contact['ContactID'];

        $patch = $this->withHeaders($this->authHeaders())
                      ->withBodyFormat('json')
                      ->call('patch', "{$this->endpoint}/{$id}", ['Specialty' => 'Pathology']);

        $patch->assertStatus(200);
        $showData = json_decode($this->withHeaders($this->authHeaders())
                                     ->call('get', "{$this->endpoint}/{$id}")
                                     ->getJSON(), true)['data'];

        $this->assertEquals('Pathology', $showData['Specialty']);
    }

    public function testPartialUpdateContactDetailOperations()
    {
        $contact = $this->createContact([
            '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',
                ],
            ],
        ]);

        $showBefore = $this->withHeaders($this->authHeaders())
                           ->call('get', "{$this->endpoint}/{$contact['ContactID']}");
        $showBefore->assertStatus(200);
        $beforeData = json_decode($showBefore->getJSON(), true)['data'];
        $keepDetail = $beforeData['Details'][0];
        $deleteDetail = $beforeData['Details'][1];

        $patch = $this->withHeaders($this->authHeaders())
                      ->withBodyFormat('json')
                      ->call('patch', "{$this->endpoint}/{$contact['ContactID']}", [
                          'Details' => [
                              'edited' => [
                                  [
                                      'ContactDetID' => $keepDetail['ContactDetID'],
                                      'JobTitle' => 'Senior Doctor',
                                      'ContactStartDate' => '2026-04-16T07:22:44.000Z',
                                  ],
                              ],
                              'created' => [
                                  [
                                      'SiteID' => '3',
                                      'ContactCode' => 'CODE3',
                                      'ContactEmail' => 'code3@example.com',
                                      'OccupationID' => '3',
                                      'JobTitle' => 'Consultant',
                                      'Department' => 'Pathology',
                                  ],
                              ],
                              'deleted' => [$deleteDetail['ContactDetID']],
                          ],
                      ]);

        $patch->assertStatus(200);

        $showAfter = $this->withHeaders($this->authHeaders())
                          ->call('get', "{$this->endpoint}/{$contact['ContactID']}");
        $showAfter->assertStatus(200);
        $afterData = json_decode($showAfter->getJSON(), true)['data'];

        $this->assertCount(2, $afterData['Details']);
        $detailIds = array_column($afterData['Details'], 'ContactDetID');
        $this->assertContains($keepDetail['ContactDetID'], $detailIds);
        $this->assertNotContains($deleteDetail['ContactDetID'], $detailIds);

        $updatedDetails = array_values(array_filter(
            $afterData['Details'],
            static fn ($row) => $row['ContactDetID'] === $keepDetail['ContactDetID']
        ));
        $this->assertNotEmpty($updatedDetails);
        $this->assertSame('Senior Doctor', $updatedDetails[0]['JobTitle']);

        $createdDetails = array_values(array_filter(
            $afterData['Details'],
            static fn ($row) => (string) $row['SiteID'] === '3'
        ));
        $this->assertNotEmpty($createdDetails);
    }
}
