<?php

namespace Tests\Feature\v2\master\TestDef;

use Tests\Support\v2\MasterTestCase;

/**
 * Feature tests for GROUP type test definitions
 * 
 * Tests GROUP-specific functionality including member management
 */
class TestDefGroupTest extends MasterTestCase
{
  protected string $endpoint = 'v2/master/tests';

  /**
   * Test create GROUP with members
   */
  public function testCreateGroupWithMembers(): void
  {
    // Get existing test IDs to use as members
    $memberIds = $this->getExistingTestIds();

    $groupData = [
      'SiteID' => 1,
      'TestSiteCode' => 'GRUP' . substr(time(), -4),
      'TestSiteName' => 'Test Group ' . time(),
      'TestType' => $this::TEST_TYPE_GROUP,
      'Description' => 'Group test with members',
      'SeqScr' => 100,
      'SeqRpt' => 100,
      'VisibleScr' => 1,
      'VisibleRpt' => 1,
      'CountStat' => 1,
      'Members' => $memberIds
    ];

    $result = $this->post($this->endpoint, ['body' => json_encode($groupData)]);

    $status = $result->response()->getStatusCode();
    $this->assertTrue(
      in_array($status, [201, 400, 500]),
      "Expected 201, 400, or 500, got $status"
    );

    if ($status === 201) {
      $body = json_decode($result->response()->getBody(), true);
      $this->assertEquals('created', $body['status']);

      // Verify members were created
      $groupId = $body['data']['TestSiteId'];
      $showResult = $this->get($this->endpoint . '/' . $groupId);
      $showBody = json_decode($showResult->response()->getBody(), true);

      if ($showBody['data'] !== null) {
        $this->assertArrayHasKey('testdefgrp', $showBody['data']);
      }
    }
  }

  /**
   * Test create GROUP without members
   */
  public function testCreateGroupWithoutMembers(): void
  {
    $groupData = [
      'SiteID' => 1,
      'TestSiteCode' => 'GREM' . substr(time(), -4),
      'TestSiteName' => 'Empty Group ' . time(),
      'TestType' => $this::TEST_TYPE_GROUP,
      'Members' => [] // Empty members
    ];

    $result = $this->post($this->endpoint, ['body' => json_encode($groupData)]);

    // Should still succeed but with warning or empty members
    $status = $result->response()->getStatusCode();
    $this->assertTrue(
      in_array($status, [201, 400]),
      "Expected 201 or 400, got $status"
    );
  }

  /**
   * Test update GROUP members
   */
  public function testUpdateGroupMembers(): void
  {
    // Create a group first
    $memberIds = $this->getExistingTestIds();
    $groupData = $this->createGroupData($memberIds);
    $groupData['TestSiteCode'] = 'UPMB' . substr(time(), -4);

    $createResult = $this->post($this->endpoint, ['body' => json_encode($groupData)]);
    $createStatus = $createResult->response()->getStatusCode();

    if ($createStatus === 201) {
      $createBody = json_decode($createResult->response()->getBody(), true);
      $groupId = $createBody['data']['TestSiteId'] ?? null;

      if ($groupId) {
        // Update with new members
        $updateData = [
          'Members' => array_slice($memberIds, 0, 1) // Only one member
        ];

        $updateResult = $this->put($this->endpoint . '/' . $groupId, ['body' => json_encode($updateData)]);
        $updateStatus = $updateResult->response()->getStatusCode();

        $this->assertTrue(
          in_array($updateStatus, [200, 400, 500]),
          "Expected 200, 400, or 500, got $updateStatus"
        );
      }
    }
  }

  /**
   * Test add member to existing GROUP
   */
  public function testAddMemberToGroup(): void
  {
    // Get existing test
    $indexResult = $this->get($this->endpoint . '?TestType=GROUP');
    $indexBody = json_decode($indexResult->response()->getBody(), true);

    if (isset($indexBody['data']) && is_array($indexBody['data']) && !empty($indexBody['data'])) {
      $group = $indexBody['data'][0];
      $groupId = $group['TestSiteID'] ?? null;

      if ($groupId) {
        // Get a test ID to add
        $testIds = $this->getExistingTestIds();
        $newMemberId = $testIds[0] ?? 1;

        $updateData = [
          'Members' => [$newMemberId]
        ];

        $result = $this->put($this->endpoint . '/' . $groupId, ['body' => json_encode($updateData)]);
        $status = $result->response()->getStatusCode();

        $this->assertTrue(
          in_array($status, [200, 400, 500]),
          "Expected 200, 400, or 500, got $status"
        );
      }
    }
  }

  /**
   * Test GROUP with single member
   */
  public function testGroupWithSingleMember(): void
  {
    $memberIds = $this->getExistingTestIds();

    $groupData = [
      'SiteID' => 1,
      'TestSiteCode' => 'GSGL' . substr(time(), -4),
      'TestSiteName' => 'Single Member Group ' . time(),
      'TestType' => $this::TEST_TYPE_GROUP,
      'Members' => [array_slice($memberIds, 0, 1)[0] ?? 1]
    ];

    $result = $this->post($this->endpoint, ['body' => json_encode($groupData)]);

    $status = $result->response()->getStatusCode();
    $this->assertTrue(
      in_array($status, [201, 400, 500]),
      "Expected 201, 400, or 500, got $status"
    );
  }

  /**
   * Test GROUP members have correct structure
   */
  public function testGroupMembersStructure(): void
  {
    $indexResult = $this->get($this->endpoint . '?TestType=GROUP');
    $indexBody = json_decode($indexResult->response()->getBody(), true);

    if (isset($indexBody['data']) && is_array($indexBody['data']) && !empty($indexBody['data'])) {
      $group = $indexBody['data'][0];
      $groupId = $group['TestSiteID'] ?? null;

      if ($groupId) {
        $showResult = $this->get($this->endpoint . '/' . $groupId);
        $showBody = json_decode($showResult->response()->getBody(), true);

        if ($showBody['data'] !== null && isset($showBody['data']['testdefgrp'])) {
          $members = $showBody['data']['testdefgrp'];

          if (is_array($members) && !empty($members)) {
            $firstMember = $members[0];

            // Check required fields in member structure
            $this->assertArrayHasKey('TestGrpID', $firstMember);
            $this->assertArrayHasKey('TestSiteID', $firstMember);
            $this->assertArrayHasKey('Member', $firstMember);

            // Check for joined test details (if loaded)
            if (isset($firstMember['TestSiteCode'])) {
              $this->assertArrayHasKey('TestSiteName', $firstMember);
            }
          }
        }
      }
    }
  }

  /**
   * Test GROUP delete cascades to members
   */
  public function testGroupDeleteCascadesToMembers(): void
  {
    // Create a group
    $memberIds = $this->getExistingTestIds();
    $groupData = $this->createGroupData($memberIds);
    $groupData['TestSiteCode'] = 'GDEL' . substr(time(), -4);

    $createResult = $this->post($this->endpoint, ['body' => json_encode($groupData)]);
    $createStatus = $createResult->response()->getStatusCode();

    if ($createStatus === 201) {
      $createBody = json_decode($createResult->response()->getBody(), true);
      $groupId = $createBody['data']['TestSiteId'] ?? null;

      if ($groupId) {
        // Delete the group
        $deleteResult = $this->delete($this->endpoint . '/' . $groupId);
        $deleteStatus = $deleteResult->response()->getStatusCode();

        $this->assertTrue(
          in_array($deleteStatus, [200, 404, 500]),
          "Expected 200, 404, or 500, got $deleteStatus"
        );

        if ($deleteStatus === 200) {
          // Verify group members are also soft deleted
          $showResult = $this->get($this->endpoint . '/' . $groupId);
          $showBody = json_decode($showResult->response()->getBody(), true);

          // Group should show EndDate set
          if ($showBody['data'] !== null) {
            $this->assertNotNull($showBody['data']['EndDate']);
          }
        }
      }
    }
  }

  /**
   * Test GROUP type has correct TypeCode in response
   */
  public function testGroupTypeCodeInResponse(): void
  {
    $indexResult = $this->get($this->endpoint . '?TestType=GROUP');
    $indexBody = json_decode($indexResult->response()->getBody(), true);

    if (isset($indexBody['data']) && is_array($indexBody['data']) && !empty($indexBody['data'])) {
      $group = $indexBody['data'][0];

      // Verify TypeCode is GROUP
      $this->assertEquals('GROUP', $group['TypeCode'] ?? '');
    }
  }

  /**
   * Helper to get existing test IDs
   */
  private function getExistingTestIds(): array
  {
    $indexResult = $this->get($this->endpoint);
    $indexBody = json_decode($indexResult->response()->getBody(), true);

    $ids = [];
    if (isset($indexBody['data']) && is_array($indexBody['data'])) {
      foreach ($indexBody['data'] as $item) {
        if (isset($item['TestSiteID'])) {
          $ids[] = $item['TestSiteID'];
        }
        if (count($ids) >= 3) {
          break;
        }
      }
    }

    return $ids ?: [1, 2, 3];
  }
}
