<?php

namespace Tests\Feature\v2\master\TestDef;

use Tests\Support\v2\MasterTestCase;

/**
 * Feature tests for PARAM type test definitions
 * 
 * Tests PARAM-specific functionality as sub-test components
 */
class TestDefParamTest extends MasterTestCase
{
  protected string $endpoint = 'v2/master/tests';

  /**
   * Test create PARAM type test
   */
  public function testCreateParamTypeTest(): void
  {
    $paramData = [
      'SiteID' => 1,
      'TestSiteCode' => 'PARM' . substr(time(), -4),
      'TestSiteName' => 'Parameter Test ' . time(),
      'TestType' => $this::TEST_TYPE_PARAM,
      'Description' => 'Parameter/sub-test description',
      'SeqScr' => 5,
      'SeqRpt' => 5,
      'VisibleScr' => 1,
      'VisibleRpt' => 1,
      'CountStat' => 1,
      'details' => [
        'DisciplineID' => 1,
        'DepartmentID' => 1,
        'ResultType' => 1, // Numeric
        'RefType' => 1, // NMRC
        'Unit1' => 'unit',
        'Decimal' => 1,
        'Method' => 'Parameter Method'
      ]
    ];

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

    $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 tech details were created
      $paramId = $body['data']['TestSiteId'];
      $showResult = $this->get($this->endpoint . '/' . $paramId);
      $showBody = json_decode($showResult->response()->getBody(), true);

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

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

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

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

  /**
   * Test PARAM details structure
   */
  public function testParamDetailsStructure(): void
  {
    $indexResult = $this->get($this->endpoint . '?TestType=PARAM');
    $indexBody = json_decode($indexResult->response()->getBody(), true);

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

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

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

          if (is_array($techDetails) && !empty($techDetails)) {
            $firstDetail = $techDetails[0];

            // Check required fields in tech structure
            $this->assertArrayHasKey('TestTechID', $firstDetail);
            $this->assertArrayHasKey('TestSiteID', $firstDetail);
            $this->assertArrayHasKey('ResultType', $firstDetail);
            $this->assertArrayHasKey('RefType', $firstDetail);

            // Check for joined discipline/department
            if (isset($firstDetail['DisciplineName'])) {
              $this->assertArrayHasKey('DepartmentName', $firstDetail);
            }
          }
        }
      }
    }
  }

  /**
   * Test PARAM with different result types
   */
  public function testParamWithDifferentResultTypes(): void
  {
    $resultTypes = [
      1 => 'NMRIC',  // Numeric
      2 => 'RANGE',  // Range
      3 => 'TEXT',   // Text
      4 => 'VSET'    // Value Set
    ];

    foreach ($resultTypes as $resultTypeId => $resultTypeName) {
      $paramData = [
        'SiteID' => 1,
        'TestSiteCode' => 'PR' . substr(time(), -4) . substr($resultTypeName, 0, 1),
        'TestSiteName' => "Param with $resultTypeName",
        'TestType' => $this::TEST_TYPE_PARAM,
        'details' => [
          'ResultType' => $resultTypeId,
          'RefType' => 1
        ]
      ];

      $result = $this->post($this->endpoint, ['body' => json_encode($paramData)]);
      $status = $result->response()->getStatusCode();

      $this->assertTrue(
        in_array($status, [201, 400, 500]),
        "PARAM with ResultType $resultTypeName: Expected 201, 400, or 500, got $status"
      );
    }
  }

  /**
   * Test PARAM with different reference types
   */
  public function testParamWithDifferentRefTypes(): void
  {
    $refTypes = [
      1 => 'NMRC',  // Numeric
      2 => 'TEXT'   // Text
    ];

    foreach ($refTypes as $refTypeId => $refTypeName) {
      $paramData = [
        'SiteID' => 1,
        'TestSiteCode' => 'PR' . substr(time(), -4) . 'R' . substr($refTypeName, 0, 1),
        'TestSiteName' => "Param with RefType $refTypeName",
        'TestType' => $this::TEST_TYPE_PARAM,
        'details' => [
          'ResultType' => 1,
          'RefType' => $refTypeId
        ]
      ];

      $result = $this->post($this->endpoint, ['body' => json_encode($paramData)]);
      $status = $result->response()->getStatusCode();

      $this->assertTrue(
        in_array($status, [201, 400, 500]),
        "PARAM with RefType $refTypeName: Expected 201, 400, or 500, got $status"
      );
    }
  }

  /**
   * Test PARAM delete cascades to details
   */
  public function testParamDeleteCascadesToDetails(): void
  {
    // Create a PARAM
    $paramData = [
      'SiteID' => 1,
      'TestSiteCode' => 'PDEL' . substr(time(), -4),
      'TestSiteName' => 'Param to Delete',
      'TestType' => $this::TEST_TYPE_PARAM,
      'details' => [
        'ResultType' => 1,
        'RefType' => 1
      ]
    ];

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

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

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

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

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

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

  /**
   * Test PARAM visibility settings
   */
  public function testParamVisibilitySettings(): void
  {
    $visibilityCombinations = [
      ['VisibleScr' => 1, 'VisibleRpt' => 1],
      ['VisibleScr' => 1, 'VisibleRpt' => 0],
      ['VisibleScr' => 0, 'VisibleRpt' => 1],
      ['VisibleScr' => 0, 'VisibleRpt' => 0]
    ];

    foreach ($visibilityCombinations as $vis) {
      $paramData = [
        'SiteID' => 1,
        'TestSiteCode' => 'PVIS' . substr(time(), -4),
        'TestSiteName' => 'Visibility Test',
        'TestType' => $this::TEST_TYPE_PARAM,
        'VisibleScr' => $vis['VisibleScr'],
        'VisibleRpt' => $vis['VisibleRpt']
      ];

      $result = $this->post($this->endpoint, ['body' => json_encode($paramData)]);
      $status = $result->response()->getStatusCode();

      $this->assertTrue(
        in_array($status, [201, 400, 500]),
        "PARAM visibility ({$vis['VisibleScr']}, {$vis['VisibleRpt']}): Expected 201, 400, or 500, got $status"
      );
    }
  }

  /**
   * Test PARAM sequence ordering
   */
  public function testParamSequenceOrdering(): void
  {
    $paramData = [
      'SiteID' => 1,
      'TestSiteCode' => 'PSEQ' . substr(time(), -4),
      'TestSiteName' => 'Sequenced Param',
      'TestType' => $this::TEST_TYPE_PARAM,
      'SeqScr' => 25,
      'SeqRpt' => 30
    ];

    $result = $this->post($this->endpoint, ['body' => json_encode($paramData)]);
    $status = $result->response()->getStatusCode();

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