<?php

namespace App\Controllers\Api;

use App\Controllers\BaseController;
use CodeIgniter\API\ResponseTrait;
use App\Models\Master\MasterControlsModel;
use App\Models\Master\MasterTestsModel;
use App\Models\Qc\ResultsModel;
use App\Models\Qc\ControlTestsModel;
use App\Models\Qc\TestCommentsModel;

class EntryApiController extends BaseController
{
    use ResponseTrait;

    protected $controlModel;
    protected $testModel;
    protected $resultModel;
    protected $controlTestModel;
    protected $commentModel;

    public function __construct()
    {
        $this->controlModel = new MasterControlsModel();
        $this->testModel = new MasterTestsModel();
        $this->resultModel = new ResultsModel();
        $this->controlTestModel = new ControlTestsModel();
        $this->commentModel = new TestCommentsModel();
    }

    /**
     * GET /api/entry/controls
     * Get controls by dept (optional dept param)
     * Optionally filter by date: only non-expired controls
     */
    public function getControls()
    {
        try {
            $keyword = $this->request->getGet('keyword');
            $deptId = $this->request->getGet('dept_id');
            $date = $this->request->getGet('date');

            $controls = $this->controlModel->search($keyword, $deptId);

            // Debug logging
            log_message('debug', 'getControls: keyword=' . var_export($keyword, true) . ', deptId=' . var_export($deptId, true) . ', date=' . var_export($date, true) . ', found=' . count($controls));

            // Filter expired controls if date provided
            if ($date) {
                $controls = array_filter($controls, function ($c) use ($date) {
                    return $c['expDate'] === null || $c['expDate'] >= $date;
                });
            }

            // Convert to camelCase (BaseModel already returns camelCase)
            $data = array_map(function ($c) {
                return [
                    'id' => $c['controlId'],
                    'controlId' => $c['controlId'],
                    'controlName' => $c['controlName'],
                    'lot' => $c['lot'],
                    'producer' => $c['producer'],
                    'expDate' => $c['expDate'],
                    'deptName' => $c['deptName'] ?? null
                ];
            }, $controls);

            log_message('debug', 'getControls: returning ' . count($data) . ' controls');

            return $this->respond([
                'status' => 'success',
                'message' => 'fetch success',
                'data' => $data
            ], 200);
        } catch (\Exception $e) {
            log_message('error', 'getControls error: ' . $e->getMessage());
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * GET /api/entry/tests
     * Get tests for a control (by control_id)
     */
    public function getTests()
    {
        try {
            $controlId = $this->request->getGet('control_id');

            if (!$controlId) {
                return $this->failValidationErrors(['control_id' => 'Required']);
            }

            $tests = $this->controlTestModel->getByControl((int) $controlId);

            return $this->respond([
                'status' => 'success',
                'message' => 'fetch success',
                'data' => $tests
            ], 200);
        } catch (\Exception $e) {
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * GET /api/entry/daily
     * Get existing results for date+control
     */
    public function getDailyData()
    {
        try {
            $date = $this->request->getGet('date');
            $controlId = $this->request->getGet('control_id');

            if (!$date || !$controlId) {
                return $this->failValidationErrors(['date' => 'Required', 'control_id' => 'Required']);
            }

            // Get tests for this control
            $tests = $this->controlTestModel->getByControl((int) $controlId);

            // Get existing results for this date
            $existingResults = $this->resultModel->getByDateAndControl($date, (int) $controlId);

            // Map existing results by test_id
            $resultsByTest = [];
            foreach ($existingResults as $r) {
                $resultsByTest[$r['testId']] = [
                    'resultId' => $r['id'],
                    'resValue' => $r['resValue'],
                    'resComment' => $r['resComment']
                ];
            }

            // Get all test IDs for this control
            $testIds = array_column($tests, 'testId');
            
            // Fetch comments separately from test_comments table (comments are per test + date)
            $commentsData = [];
            if (!empty($testIds)) {
                $comments = $this->commentModel->getByTestAndDateRange($testIds, $date, $date);
                foreach ($comments as $c) {
                    $commentsData[$c['testId']] = $c['commentText'];
                }
            }

            // Merge tests with existing values and comments
            $data = [];
            foreach ($tests as $t) {
                $existing = $resultsByTest[$t['testId']] ?? null;
                
                // Get comment from either the test_comments table or existing result
                $comment = $commentsData[$t['testId']] ?? null;
                if ($existing && isset($existing['resComment']) && $existing['resComment']) {
                    $comment = $existing['resComment']; // Existing result's comment takes precedence
                }
                
                $data[] = [
                    'controlTestId' => $t['id'],
                    'controlId' => $t['controlId'],
                    'testId' => $t['testId'],
                    'testName' => $t['testName'],
                    'testUnit' => $t['testUnit'],
                    'mean' => $t['mean'],
                    'sd' => $t['sd'],
                    'existingResult' => $existing,
                    'comment' => $comment
                ];
            }

            return $this->respond([
                'status' => 'success',
                'message' => 'fetch success',
                'data' => $data
            ], 200);
        } catch (\Exception $e) {
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * POST /api/entry/daily
     * Save/update daily results (batch)
     */
    public function saveDaily()
    {
        try {
            $input = $this->request->getJSON(true);

            if (!isset($input['date']) || !isset($input['results']) || !is_array($input['results'])) {
                return $this->failValidationErrors(['Invalid input']);
            }

            $date = $input['date'];
            $results = $input['results'];
            $deletedIds = $input['deletedIds'] ?? [];
            $savedIds = [];

            // Start transaction
            $this->resultModel->db->transBegin();

            // Handle deletions first
            foreach ($deletedIds as $resultId) {
                $this->resultModel->delete((int) $resultId);
            }

            // Save/update results
            foreach ($results as $r) {
                if (!isset($r['controlId']) || !isset($r['testId']) || !isset($r['value'])) {
                    continue;
                }

                $data = [
                    'control_id' => $r['controlId'],
                    'test_id' => $r['testId'],
                    'res_date' => $date,
                    'res_value' => $r['value'] !== '' ? (float) $r['value'] : null
                ];

                if ($data['res_value'] === null) {
                    continue; // Skip empty values
                }

                $resultId = $this->resultModel->upsertResult($data);
                $savedIds[] = [
                    'testId' => $r['testId'],
                    'resultId' => $resultId
                ];
            }

            // Commit transaction
            $this->resultModel->db->transCommit();

            return $this->respond([
                'status' => 'success',
                'message' => 'Saved ' . count($savedIds) . ' results' . (count($deletedIds) > 0 ? ', deleted ' . count($deletedIds) : ''),
                'data' => ['savedIds' => $savedIds]
            ], 200);
        } catch (\Exception $e) {
            // Rollback transaction on error
            $this->resultModel->db->transRollback();
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * GET /api/entry/monthly
     * Get monthly data by test
     */
    public function getMonthlyData()
    {
        try {
            $testId = $this->request->getGet('test_id');
            $month = $this->request->getGet('month'); // YYYY-MM

            if (!$testId || !$month) {
                return $this->failValidationErrors(['test_id' => 'Required', 'month' => 'Required']);
            }

            // Get test details
            $test = $this->testModel->find($testId);
            if (!$test) {
                return $this->failNotFound('Test not found');
            }

            // Get controls for this test with QC parameters (filter out expired)
            $controls = $this->controlTestModel->getByTest((int) $testId, $month);

            // Get existing results for this month
            $results = $this->resultModel->getByMonth((int) $testId, $month);

            // Get comments for this test (test_id + date based)
            $comments = $this->commentModel->getByTestAndMonth((int) $testId, $month);

            // Map results by control_id and day
            $resultsByControl = [];
            foreach ($results as $r) {
                $day = (int) date('j', strtotime($r['resDate']));
                $resultsByControl[$r['controlId']][$day] = [
                    'resultId' => $r['id'],
                    'resValue' => $r['resValue'],
                    'resDate' => $r['resDate']
                ];
            }

            // Map comments by date (comments are now per test + date)
            $commentsByDate = [];
            foreach ($comments as $c) {
                $commentsByDate[$c['commentDate']] = [
                    'commentId' => $c['testCommentId'],
                    'commentText' => $c['commentText']
                ];
            }

            // Build controls with results array[31]
            $controlsWithData = [];
            foreach ($controls as $c) {
                $resultsByDay = $resultsByControl[$c['controlId']] ?? [];
                $resultsArray = array_fill(1, 31, null);

                foreach ($resultsByDay as $day => $val) {
                    $resultWithComment = $val;
                    // Add comment if exists for this date (comments are per test + date)
                    $resultDate = date('Y-m-d', strtotime($val['resDate']));
                    if (isset($commentsByDate[$resultDate])) {
                        $resultWithComment['resComment'] = $commentsByDate[$resultDate]['commentText'];
                    } else {
                        $resultWithComment['resComment'] = null;
                    }
                    $resultsArray[$day] = $resultWithComment;
                }

                $controlsWithData[] = [
                    'controlTestId' => $c['id'],
                    'controlId' => $c['controlId'],
                    'controlName' => $c['controlName'],
                    'lot' => $c['lot'],
                    'producer' => $c['producer'],
                    'mean' => $c['mean'],
                    'sd' => $c['sd'],
                    'results' => $resultsArray
                ];
            }

            $data = [
                'test' => [
                    'testId' => $test['testId'],
                    'testName' => $test['testName'],
                    'testUnit' => $test['testUnit']
                ],
                'month' => $month,
                'controls' => $controlsWithData
            ];

            return $this->respond([
                'status' => 'success',
                'message' => 'fetch success',
                'data' => $data
            ], 200);
        } catch (\Exception $e) {
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * POST /api/entry/monthly
     * Save monthly batch (results + comments)
     */
    public function saveMonthly()
    {
        try {
            $input = $this->request->getJSON(true);

            if (!isset($input['testId']) || !isset($input['month']) || !isset($input['controls'])) {
                return $this->failValidationErrors(['Invalid input']);
            }

            $testId = $input['testId'];
            $month = $input['month'];
            $controls = $input['controls'];

            // Validate month has valid days
            $daysInMonth = (int) date('t', strtotime($month . '-01'));

            $savedCount = 0;
            $resultIdMap = []; // Map controlId + day -> resultId

            // Start transaction
            $this->resultModel->db->transBegin();

            foreach ($controls as $c) {
                $controlId = $c['controlId'];
                $results = $c['results'] ?? [];

                // Save results with optional comments
                foreach ($results as $day => $data) {
                    // Handle both old format (value only) and new format (value + comment)
                    if (is_array($data)) {
                        $value = $data['value'];
                        $commentText = $data['comment'] ?? null;
                    } else {
                        $value = $data;
                        $commentText = null;
                    }

                    if ($value === null || $value === '') {
                        continue;
                    }

                    // Validate day exists in month
                    if ($day < 1 || $day > $daysInMonth) {
                        continue;
                    }

                    $date = $month . '-' . str_pad($day, 2, '0', STR_PAD_LEFT);
                    $resultData = [
                        'control_id' => $controlId,
                        'test_id' => $testId,
                        'res_date' => $date,
                        'res_value' => (float) $value
                    ];

                    $resultId = $this->resultModel->upsertResult($resultData);
                    $resultIdMap["{$controlId}_{$day}"] = $resultId;
                    $savedCount++;
                }
            }

            // Commit transaction
            $this->resultModel->db->transCommit();

            return $this->respond([
                'status' => 'success',
                'message' => "Saved {$savedCount} results",
                'data' => [
                    'savedCount' => $savedCount,
                    'resultIdMap' => $resultIdMap
                ]
            ], 200);
        } catch (\Exception $e) {
            // Rollback transaction on error
            $this->resultModel->db->transRollback();
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * POST /api/entry/comment
     * Save daily comment (single)
     */
    public function saveComment()
    {
        try {
            $input = $this->request->getJSON(true);

            $required = ['testId', 'date', 'comment'];
            foreach ($required as $field) {
                if (!isset($input[$field])) {
                    return $this->failValidationErrors([$field => 'Required']);
                }
            }

            $commentData = [
                'test_id' => $input['testId'],
                'comment_date' => $input['date'],
                'comment_text' => trim($input['comment'])
            ];

            $id = $this->commentModel->upsertComment($commentData);

            return $this->respond([
                'status' => 'success',
                'message' => 'Comment saved',
                'data' => ['id' => $id]
            ], 200);
        } catch (\Exception $e) {
            return $this->failServerError('Something went wrong: ' . $e->getMessage());
        }
    }
}
