<?php

namespace App\Controllers;

use App\Traits\PatchValidationTrait;
use App\Traits\ResponseTrait;
use CodeIgniter\Controller;
use App\Models\PatResultModel;
use Config\Services;

class ResultController extends Controller {
    use ResponseTrait;
    use PatchValidationTrait;

    protected $model;

    public function __construct() {
        $this->model = new PatResultModel();
    }

    /**
     * List results with optional filters
     * GET /api/result
     */
    public function index() {
        try {
            $orderID = $this->request->getGet('order_id');
            $patientID = $this->request->getGet('patient_id');

            if ($orderID) {
                $results = $this->model->getByOrder((int)$orderID);
            } elseif ($patientID) {
                $results = $this->model->getByPatient((int)$patientID);
            } else {
                // Get all results with pagination
                $page = (int)($this->request->getGet('page') ?? 1);
                $perPage = (int)($this->request->getGet('per_page') ?? 20);
                
                $results = $this->model
                    ->where('DelDate', null)
                    ->orderBy('ResultID', 'DESC')
                    ->paginate($perPage, 'default', $page);
            }

            $results = is_array($results)
                ? array_map([$this, 'hydrateResultPayload'], $results)
                : $results;

            return $this->respond([
                'status' => 'success',
                'message' => 'Results retrieved successfully',
                'data' => $results
            ], 200);

        } catch (\Exception $e) {
            log_message('error', 'ResultController::index error: ' . $e->getMessage());
            return $this->respond([
                'status' => 'failed',
                'message' => 'Failed to retrieve results',
                'data' => []
            ], 500);
        }
    }

    /**
     * Get single result
     * GET /api/result/{id}
     */
    public function show($id) {
        try {
            $result = $this->model->getWithRelations((int)$id);

            if (!$result) {
                return $this->respond([
                    'status' => 'failed',
                    'message' => 'Result not found',
                    'data' => []
                ], 404);
            }

            $result = $this->hydrateResultPayload($result);

            return $this->respond([
                'status' => 'success',
                'message' => 'Result retrieved successfully',
                'data' => $result
            ], 200);

        } catch (\Exception $e) {
            log_message('error', 'ResultController::show error: ' . $e->getMessage());
            return $this->respond([
                'status' => 'failed',
                'message' => 'Failed to retrieve result',
                'data' => []
            ], 500);
        }
    }

    /**
     * Create a new result entry
     * POST /api/result
     */
    public function create() {
        $payload = $this->request->getJSON(true);
        if (!is_array($payload) || empty($payload)) {
            return $this->respond([
                'status' => 'failed',
                'message' => 'No data provided',
                'data' => []
            ], 400);
        }

        if (isset($payload['ResultValue'])) {
            $payload['Result'] = $payload['ResultValue'];
        }

        $dbPayload = $payload;
        unset($dbPayload['ResultValue'], $dbPayload['ResultCode']);

        try {
            $resultId = $this->model->insert($dbPayload, true);

            if (!$resultId) {
                return $this->respond([
                    'status' => 'failed',
                    'message' => 'Failed to create result',
                    'data' => []
                ], 500);
            }

            $this->rememberResultCode($resultId, $payload['ResultCode'] ?? null);

            return $this->respondCreated([
                'status' => 'success',
                'message' => 'Result created successfully',
                'data' => [
                    'ResultID' => $resultId,
                    'ResultValue' => $payload['ResultValue'] ?? ($payload['Result'] ?? null),
                    'ResultCode' => $payload['ResultCode'] ?? null,
                ]
            ], 201);
        } catch (\Exception $e) {
            log_message('error', 'ResultController::create error: ' . $e->getMessage());
            return $this->respond([
                'status' => 'failed',
                'message' => 'Failed to create result',
                'data' => []
            ], 500);
        }
    }

    /**
     * Update result with validation
     * PATCH /api/result/{id}
     */
    public function update($id) {
        try {
            $data = $this->requirePatchPayload($this->request->getJSON(true));
            if ($data === null) {
                return;
            }

            $validatedId = $this->requirePatchId($id, 'ResultID');
            if ($validatedId === null) {
                return;
            }

            $existing = $this->model->find($validatedId);
            if (!$existing) {
                return $this->respond([
                    'status' => 'failed',
                    'message' => 'Result not found',
                    'data' => []
                ], 404);
            }

		$resultCode = $data['ResultCode'] ?? null;
		$hasResultValue = array_key_exists('ResultValue', $data);

		if ($hasResultValue) {
			$data['Result'] = $data['ResultValue'];
		}

		unset($data['ResultValue'], $data['ResultCode']);

		$shouldUpdateModel = $hasResultValue || !empty($data);

		if ($shouldUpdateModel) {
			$result = $this->model->updateWithValidation($validatedId, $data);
		} else {
			$result = [
				'success' => true,
				'flag' => null,
				'message' => 'Result updated successfully'
			];
		}

		if (!$result['success']) {
			return $this->respond([
				'status' => 'failed',
				'message' => $result['message'],
				'data' => []
			], 400);
		}

		if ($resultCode !== null) {
			$this->rememberResultCode($validatedId, $resultCode);
		}

            // Get updated result with relations
            $updatedResult = $this->model->getWithRelations($validatedId);

            return $this->respond([
                'status' => 'success',
                'message' => $result['message'],
                'data' => [
                    'result' => $updatedResult ? $this->hydrateResultPayload($updatedResult) : [],
                    'flag' => $result['flag']
                ]
            ], 200);

        } catch (\Exception $e) {
            log_message('error', 'ResultController::update error: ' . $e->getMessage());
            return $this->respond([
                'status' => 'failed',
                'message' => 'Failed to update result',
                'data' => []
            ], 500);
        }
    }

    /**
     * Soft delete result
     * DELETE /api/result/{id}
     */
    public function delete($id) {
        try {
            $result = $this->model->find((int)$id);

            if (!$result) {
                return $this->respond([
                    'status' => 'failed',
                    'message' => 'Result not found',
                    'data' => []
                ], 404);
            }

            $deleted = $this->model->softDelete((int)$id);

            if (!$deleted) {
                return $this->respond([
                    'status' => 'failed',
                    'message' => 'Failed to delete result',
                    'data' => []
                ], 500);
            }

            return $this->respond([
                'status' => 'success',
                'message' => 'Result deleted successfully',
                'data' => []
            ], 200);

        } catch (\Exception $e) {
            log_message('error', 'ResultController::delete error: ' . $e->getMessage());
            return $this->respond([
                'status' => 'failed',
                'message' => 'Failed to delete result',
                'data' => []
            ], 500);
        }
    }

    private function hydrateResultPayload(array $payload): array {
        if (!array_key_exists('ResultValue', $payload) && array_key_exists('Result', $payload)) {
            $payload['ResultValue'] = $payload['Result'];
        }
        return $payload;
    }
}
