<?php

namespace App\Controllers;

use App\Traits\ResponseTrait;
use App\Services\CalculatorService;
use App\Models\Test\TestDefCalModel;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\ResponseInterface;

class CalculatorController extends Controller
{
  use ResponseTrait;

  protected CalculatorService $calculator;
  protected TestDefCalModel $calcModel;

  public function __construct()
  {
    $this->calculator = new CalculatorService();
    $this->calcModel = new TestDefCalModel();
  }

  /**
   * POST api/calculate
   * Calculate a formula with provided variables
   * 
   * Request: {
   *   "formula": "{result} * {factor} + {gender}",
   *   "variables": {
   *     "result": 100,
   *     "factor": 0.5,
   *     "gender": "female"
   *   }
   * }
   */
  public function calculate(): ResponseInterface
  {
    try {
      $data = $this->request->getJSON(true);
      
      if (empty($data['formula'])) {
        return $this->respond([
          'status' => 'failed',
          'message' => 'Formula is required'
        ], 400);
      }

      $result = $this->calculator->calculate(
        $data['formula'],
        $data['variables'] ?? []
      );

      return $this->respond([
        'status' => 'success',
        'data' => [
          'result' => $result,
          'formula' => $data['formula'],
          'variables' => $data['variables'] ?? []
        ]
      ], 200);

    } catch (\Exception $e) {
      return $this->respond([
        'status' => 'failed',
        'message' => $e->getMessage()
      ], 400);
    }
  }

  /**
   * POST api/calculate/validate
   * Validate a formula syntax
   * 
   * Request: {
   *   "formula": "{result} * 2 + 5"
   * }
   */
  public function validateFormula(): ResponseInterface
  {
    try {
      $data = $this->request->getJSON(true);
      
      if (empty($data['formula'])) {
        return $this->respond([
          'status' => 'failed',
          'message' => 'Formula is required'
        ], 400);
      }

      $validation = $this->calculator->validate($data['formula']);

      return $this->respond([
        'status' => $validation['valid'] ? 'success' : 'failed',
        'data' => [
          'valid' => $validation['valid'],
          'error' => $validation['error'],
          'variables' => $this->calculator->extractVariables($data['formula'])
        ]
      ], 200);

    } catch (\Exception $e) {
      return $this->respond([
        'status' => 'failed',
        'message' => $e->getMessage()
      ], 400);
    }
  }

  /**
   * POST api/calc/testsite/{testSiteID}
   * Calculate using TestDefCal definition
   * 
   * Request: {
   *   "result": 85,
   *   "gender": "female",
   *   "age": 30
   * }
   */
  public function calculateByTestSite($testSiteID): ResponseInterface
  {
    try {
      $calcDef = $this->calcModel->existsByTestSiteID($testSiteID);
      
      if (!$calcDef) {
        return $this->respond([
          'status' => 'failed',
          'message' => 'No calculation defined for this test site'
        ], 404);
      }

      $testValues = $this->request->getJSON(true);
      $result = $this->calculator->calculateFromDefinition($calcDef, $testValues);

      return $this->respond([
        'status' => 'success',
        'data' => [
          'result' => $result,
          'testSiteID' => $testSiteID,
          'formula' => $calcDef['FormulaCode'],
          'variables' => $testValues
        ]
      ], 200);

    } catch (\Exception $e) {
      return $this->respond([
        'status' => 'failed',
        'message' => $e->getMessage()
      ], 400);
    }
  }

  /**
   * POST api/calc/testcode/{codeOrName}
   * Evaluate a configured calculation by its code or name and return only the result map.
   */
  public function calculateByCodeOrName($codeOrName): ResponseInterface
  {
    try {
      $calcDef = $this->calcModel->findActiveByCodeOrName($codeOrName);

      if (!$calcDef || empty($calcDef['FormulaCode'])) {
        return $this->response->setJSON(new \stdClass());
      }

      $input = $this->request->getJSON(true);
      $variables = is_array($input) ? $input : [];

      $result = $this->calculator->calculate($calcDef['FormulaCode'], $variables);

      if ($result === null) {
        return $this->response->setJSON(new \stdClass());
      }

      $responseKey = $calcDef['TestSiteCode'] ?? strtoupper($codeOrName);

      return $this->response->setJSON([ $responseKey => $result ]);
    } catch (\Exception $e) {
      log_message('error', "Calc lookup failed for {$codeOrName}: " . $e->getMessage());
      return $this->response->setJSON(new \stdClass());
    }
  }
}
