<?php

namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use App\Controllers\BaseController;
use App\Models\AgentModel;
use App\Models\AgentIncentiveFileModel;
use App\Models\PartnerRetentionRateModel;


class AgentController extends ResourceController
{
    protected $db;
    protected $AgentModel;
    protected $AgentIncentiveFileModel;
    protected $PartnerRetentionRateModel;


    public function __construct()
    {
        $this->db = db_connect();
        $this->AgentModel = new AgentModel();
        $this->AgentIncentiveFileModel = new AgentIncentiveFileModel();
        $this->PartnerRetentionRateModel = new PartnerRetentionRateModel();

    }

    /**
     * @return list<array{vehicle_type_id:int|float, segment_id:int|float, retention_rate:float}>
     */
    protected function parseRetentionRatesFromRequest(): array
    {
        $raw = $this->request->getPost('retention_rates');
        if ($raw === null || $raw === '') {
            return [];
        }
        if (is_string($raw)) {
            $decoded = json_decode($raw, true);
        } else {
            $decoded = $raw;
        }
        if (!is_array($decoded)) {
            return [];
        }
        $out = [];
        foreach ($decoded as $row) {
            if (!is_array($row)) {
                continue;
            }
            $vtId = $row['vehicle_type_id'] ?? $row['vehicleTypeId'] ?? null;
            if ($vtId === null || $vtId === '') {
                continue;
            }
            $segmentId = $row['segment_id'] ?? $row['segmentId'] ?? null;
            if ($segmentId === null || $segmentId === '') {
                continue;
            }
            $rateRaw = $row['retention_rate'] ?? $row['retentionRate'] ?? null;
            if ($rateRaw === null || $rateRaw === '') {
                continue;
            }
            $rate = (float) $rateRaw;
            if ($rate < 0 || $rate > 100) {
                continue;
            }
            $out[] = [
                'vehicle_type_id' => (int) $vtId,
                'segment_id'      => (int) $segmentId,
                'retention_rate'  => round($rate, 2),
            ];
        }

        return $out;
    }

    /**
     * Replace retention rows for an agent from the parsed list (main Save).
     */
    protected function syncRetentionRatesForAgent(int $agentId, array $rates, ?int $userId): void
    {
        $this->PartnerRetentionRateModel->where('agent_id', $agentId)->delete();
        $now = date('Y-m-d H:i:s');
        foreach ($rates as $r) {
            $this->PartnerRetentionRateModel->insert([
                'agent_id'         => $agentId,
                'vehicle_type_id'  => $r['vehicle_type_id'],
                'segment_id'       => $r['segment_id'],
                'retention_rate'   => $r['retention_rate'],
                'is_active'        => 1,
                'created_by'       => $userId,
                'created_on'       => $now,
                'updated_by'       => null,
                'updated_on'       => null,
            ]);
        }
    }

    /** Active vehicle types for partner retention UI */
    public function partnerVehicleTypeList()
    {
        try {
            $data = $this->db->table('partner_segment ps')
                ->select('vt.id as vehicle_type_id, vt.vehicle_type, ps.id as segment_id, ps.segment')
                ->join('vehicle_type vt', 'vt.id = ps.vehicle_type_id', 'inner')
                ->where('ps.is_active', 1)
                ->where('vt.is_active', 1)
                ->orderBy('vt.vehicle_type', 'ASC')
                ->orderBy('ps.segment', 'ASC')
                ->get()
                ->getResultArray();

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => $data], 200);
        } catch (\Exception $e) {
            return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
        }
    }

    /**
     * Upsert one vehicle-type retention row (inline edit on agent details).
     */
    public function updateAgentVehicleRetention()
    {
        try {
            $data = $this->request->getJSON(true);
            if (!is_array($data) || $data === []) {
                $raw = $this->request->getRawInput();
                if (is_array($raw) && $raw !== []) {
                    $data = $raw;
                } elseif (is_string($raw) && $raw !== '') {
                    $decoded = json_decode($raw, true);
                    if (is_array($decoded)) {
                        $data = $decoded;
                    }
                }
            }
            if (!is_array($data) || $data === []) {
                $data = $this->request->getPost();
            }
            if (!is_array($data)) {
                $data = [];
            }

            if (!isset($data['agent_id'], $data['vehicle_type_id'], $data['segment_id'], $data['retention_rate'])) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'agent_id, vehicle_type_id, segment_id and retention_rate are required'], 200);
            }
            $agentId = (int) $data['agent_id'];
            $vtId    = (int) $data['vehicle_type_id'];
            $segmentId = (int) $data['segment_id'];
            $rate    = (float) $data['retention_rate'];
            if ($rate < 0 || $rate > 100) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'retention_rate must be between 0 and 100'], 200);
            }
            $agent = $this->AgentModel->find($agentId);
            if (!$agent) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'Agent not found'], 200);
            }
            $updatedBy = isset($data['updated_by']) ? (int) $data['updated_by'] : null;
            $now       = date('Y-m-d H:i:s');

            $existing = $this->PartnerRetentionRateModel
                ->where('agent_id', $agentId)
                ->where('vehicle_type_id', $vtId)
                ->where('segment_id', $segmentId)
                ->first();

            if ($existing) {
                $this->PartnerRetentionRateModel->update((int) $existing['id'], [
                    'retention_rate' => round($rate, 2),
                    'is_active'      => 1,
                    'updated_by'     => $updatedBy,
                    'updated_on'     => $now,
                ]);
            } else {
                $this->PartnerRetentionRateModel->insert([
                    'agent_id'        => $agentId,
                    'vehicle_type_id' => $vtId,
                    'segment_id'      => $segmentId,
                    'retention_rate'  => round($rate, 2),
                    'is_active'       => 1,
                    'created_by'      => $updatedBy,
                    'created_on'      => $now,
                ]);
            }

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => []], 200);
        } catch (\Exception $e) {
            return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
        }
    }

    /**
     * Bulk upsert retention rows from the retention table (Save all).
     * POST JSON or form: agent_id, updated_by, retention_rates (array of {vehicle_type_id, retention_rate}).
     * Skips invalid entries; empty retention_rates array returns an error.
     */
    public function saveAgentRetentionRatesBulk()
    {
        try {
            $data = $this->request->getJSON(true);
            if (!is_array($data) || $data === []) {
                $raw = $this->request->getRawInput();
                if (is_array($raw) && $raw !== []) {
                    $data = $raw;
                } elseif (is_string($raw) && $raw !== '') {
                    $decoded = json_decode($raw, true);
                    if (is_array($decoded)) {
                        $data = $decoded;
                    }
                }
            }
            if (!is_array($data) || $data === []) {
                $data = $this->request->getPost();
            }
            if (!is_array($data)) {
                $data = [];
            }

            if (!isset($data['agent_id'])) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'agent_id is required'], 200);
            }

            $agentId = (int) $data['agent_id'];
            $agent   = $this->AgentModel->find($agentId);
            if (!$agent) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'Agent not found'], 200);
            }

            $ratesRaw = $data['retention_rates'] ?? null;
            if ($ratesRaw === null || $ratesRaw === '') {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'retention_rates is required'], 200);
            }
            if (is_string($ratesRaw)) {
                $rates = json_decode($ratesRaw, true);
            } else {
                $rates = $ratesRaw;
            }
            if (!is_array($rates) || $rates === []) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'retention_rates must be a non-empty array'], 200);
            }

            $updatedBy = isset($data['updated_by']) ? (int) $data['updated_by'] : null;
            $now       = date('Y-m-d H:i:s');
            $saved     = 0;

            foreach ($rates as $row) {
                if (!is_array($row)) {
                    continue;
                }
                $vtId = $row['vehicle_type_id'] ?? $row['vehicleTypeId'] ?? null;
                if ($vtId === null || $vtId === '') {
                    continue;
                }
                $segmentId = $row['segment_id'] ?? $row['segmentId'] ?? null;
                if ($segmentId === null || $segmentId === '') {
                    continue;
                }
                $rateRaw = $row['retention_rate'] ?? $row['retentionRate'] ?? null;
                if ($rateRaw === null || $rateRaw === '') {
                    continue;
                }
                $rate = (float) $rateRaw;
                if ($rate < 0 || $rate > 100) {
                    continue;
                }
                $vtId = (int) $vtId;
                $segmentId = (int) $segmentId;

                $existing = $this->PartnerRetentionRateModel
                    ->where('agent_id', $agentId)
                    ->where('vehicle_type_id', $vtId)
                    ->where('segment_id', $segmentId)
                    ->first();

                if ($existing) {
                    $this->PartnerRetentionRateModel->update((int) $existing['id'], [
                        'retention_rate' => round($rate, 2),
                        'is_active'      => 1,
                        'updated_by'     => $updatedBy,
                        'updated_on'     => $now,
                    ]);
                } else {
                    $this->PartnerRetentionRateModel->insert([
                        'agent_id'        => $agentId,
                        'vehicle_type_id' => $vtId,
                        'segment_id'      => $segmentId,
                        'retention_rate'  => round($rate, 2),
                        'is_active'       => 1,
                        'created_by'      => $updatedBy,
                        'created_on'      => $now,
                    ]);
                }
                $saved++;
            }

            if ($saved === 0) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'No valid retention rows to save'], 200);
            }

            return $this->respond([
                'status' => 'success',
                'code'   => 200,
                'data'   => ['saved_count' => $saved],
            ], 200);
        } catch (\Exception $e) {
            return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
        }
    }

    // List of all agents
    public function agentList()
    {
        try{

            $id = $this->request->getGet('manager_id');

            $data = $this->AgentModel->select('partner_agent.*,partner_sales_executive.name as sales_executive_name')
            ->join('partner_sales_executive', 'partner_sales_executive.id = partner_agent.sales_executive_id', 'left')
            ->where('partner_agent.manager_id' , $id )
            ->findAll();

            if ($data !== []) {
                $ids = array_column($data, 'id');
                $db    = db_connect();
                $avgs  = $db->table('partner_retention_rate')
                    ->select('agent_id, ROUND(AVG(retention_rate), 2) AS avg_retention', false)
                    ->where('is_active', 1)
                    ->whereIn('agent_id', $ids)
                    ->groupBy('agent_id')
                    ->get()
                    ->getResultArray();
                $avgMap = [];
                foreach ($avgs as $a) {
                    $avgMap[(int) $a['agent_id']] = $a['avg_retention'];
                }
                foreach ($data as &$row) {
                    $aid = (int) $row['id'];
                    if (isset($avgMap[$aid])) {
                        $row['retention_rate'] = $avgMap[$aid];
                    }
                }
                unset($row);
            }

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => $data], 200);

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

    public function agentListForEnquiryCreationDropdown()
    {
        try{

            $id = $this->request->getGet('manager_id');

            $data = $this->AgentModel->where('manager_id' , $id )->where('is_active',1)->findAll();

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => $data], 200);

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

    // Find a agent
    public function findAgent()
    {
        try{

            $id = $this->request->getGet('id');

            $record = $this->AgentModel->find((int)$id);

            if (!$record) {
                return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200);
            }

            $rates = $this->PartnerRetentionRateModel
                ->select('partner_retention_rate.id as retention_row_id, partner_retention_rate.vehicle_type_id, partner_retention_rate.segment_id, partner_retention_rate.retention_rate, vehicle_type.vehicle_type, partner_segment.segment')
                ->join('vehicle_type', 'vehicle_type.id = partner_retention_rate.vehicle_type_id', 'left')
                ->join('partner_segment', 'partner_segment.id = partner_retention_rate.segment_id', 'left')
                ->where('partner_retention_rate.agent_id', (int) $id)
                ->where('partner_retention_rate.is_active', 1)
                ->orderBy('vehicle_type.vehicle_type', 'ASC')
                ->orderBy('partner_segment.segment', 'ASC')
                ->findAll();
            $record['retention_by_vehicle'] = $rates;

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => $record], 200);

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

    // CREATE agent
    public function createAgent()
    {
        try{
            $data = $this->request->getPost();

            // handle file uploads
            $certificateFile = $this->request->getFile('certificate_file_name');

            $certificateFileName = null;

            // certificate upload
            if ($certificateFile && $certificateFile->isValid()) {
                $uploadPath = WRITEPATH . 'uploads/agent/certificate_file/';
                if (!is_dir($uploadPath)) {
                    mkdir($uploadPath, 0777, true);
                }
                $certificateFileName = time() . '_' . $certificateFile->getRandomName();
                $certificateFile->move($uploadPath, $certificateFileName);
            }

            $rates = $this->parseRetentionRatesFromRequest();

            $insertData = [
                'name'                  => $data['name'],
                'email'                 => $data['email'],
                'mobile'                => $data['mobile'],
                'agent_code'            => $data['agent_code'],
                'address'               => $data['address'],
                'manager_id'            => $data['manager_id'],
                'sales_executive_id'    => $data['sales_executive_id'],
                'certificate_file_name' => $certificateFileName,
                'created_by'            => $data['created_by'],
                'retention_rate'        => null,
            ];

            $this->AgentModel->insert($insertData);
            $newId = (int) $this->AgentModel->getInsertID();

            if ($rates !== [] && $newId > 0) {
                $createdBy = isset($data['created_by']) ? (int) $data['created_by'] : null;
                $this->syncRetentionRatesForAgent($newId, $rates, $createdBy);
            }

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => ['agent_id' => $newId]], 200);

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

   // UPDATE agent
   public function updateAgent()
   {
        try{

            $data = $this->request->getPost();
            if (!isset($data['id'])) {
                    return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'ID Required'], 200);
                }

            $id = $data['id'];

            // check if agent exists
            $agent = $this->AgentModel->find((int)$id);
            if (!$agent) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'Date Not Found'], 200);
            }

            // handle file uploads
            $certificateFile = $this->request->getFile('certificate_file_name');

            $updateData = [
                'name'    => $data['name'] ?? null,
                'email'   => $data['email'] ?? null,
                'mobile'  => $data['mobile'] ?? null,
                'address' => $data['address'] ?? null,
                'agent_code' => $data['agent_code'] ?? null,
                'sales_executive_id'    => $data['sales_executive_id'] ?? null,
                'updated_by' => $data['updated_by'] ?? null,
                'retention_rate'     => null,
            ];

            if ($certificateFile && $certificateFile->isValid()) {
                $uploadPath = WRITEPATH . 'uploads/agent/certificate_file/';
                if (!is_dir($uploadPath)) {
                    mkdir($uploadPath, 0777, true);
                }
                $certificateFileName = time() . '_' . $certificateFile->getRandomName();
                $certificateFile->move($uploadPath, $certificateFileName);
                $updateData['certificate_file_name'] = $certificateFileName;
            }

            if (array_key_exists('retention_rates', $data)) {
                $rates     = $this->parseRetentionRatesFromRequest();
                $updatedBy = isset($data['updated_by']) ? (int) $data['updated_by'] : null;
                $this->syncRetentionRatesForAgent((int) $id, $rates, $updatedBy);
            }

            $this->AgentModel->update($id, $updateData);

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => []], 200);

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

   //update device token
   public function updateDeviceToken()
   {
        try{

            $data = $this->request->getPost();
            if (!isset($data['id'])) {
                    return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'ID Required'], 200);
                }

            $id = $data['id'];

            // check if agent exists
            $agent = $this->AgentModel->find((int)$id);
            if (!$agent) {
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'Date Not Found'], 200);
            }

           
            $updateData = [
                'firebase_device_token'    => $data['firebase_device_token'] ?? null,
            ];

            $this->AgentModel->update($id, $updateData);

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => []], 200);

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

    // ACTIVATE / DEACTIVATE agent
    public function changeAgentStatus()
    {
        try {
            $data = $this->request->getJSON(true);

            // validate inputs
            if (!isset($data['id']) || !isset($data['is_active'])) {
                return $this->respond(['status' => 'failed', 'code'   => 200,'data'   => 'ID and Status are required'], 200);
            }

            $id     = $data['id'];
            $is_active = (int) $data['is_active']; // 0 or 1

            $status = ($is_active == 1) ? 0 : 1;

            // check if agent exists
            $agent = $this->AgentModel->find((int)$id);
            if (!$agent) {
                return $this->respond(['status' => 'failed','code'   => 200, 'data'   => 'Agent not found'], 200);
            }

            // update status
            $this->AgentModel->update($id, ['is_active' => $status]);

            return $this->respond([
                'status'  => 'success', 'code'    => 200,'data'   => "Agent status updated"], 200);

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

    // Download agent certificate file
    public function downloadAgentCertificateFile()
    {
        try {
            $id = $this->request->getGet('agent_id');

            if (!$id) {
                return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'ID is required'], 200);
            }

            // Fetch record from DB
            $fileRecord = $this->AgentModel->where('is_active',1)->find((int)$id);

            if (!$fileRecord) {
                return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File not found'], 200);
            }

            $filePath = WRITEPATH . 'uploads/agent/certificate_file/' . $fileRecord['certificate_file_name'];

            if (!file_exists($filePath)) {
                return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File missing on server'], 200);
            }

            // Force file download
            return $this->response->download($filePath, null);

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

    // List of all agents incentive files
    public function agentIncentiveFileList()
    {
        try{

            $agent_id = $this->request->getGet('agent_id');
            $type     = $this->request->getGet('type');

            $fileType = (!empty($type) && $type === 'grid') ? 'grid' : 'incentive';
            $data = $this->AgentIncentiveFileModel->where('agent_id',$agent_id)->where('is_active',1)->where('file_type', $fileType)->findAll();

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => $data], 200);

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

    // Upload agent incentive file
    public function uploadAgentIncentiveFile()
    {
        try{
            $data = $this->request->getPost();

            //duplicate check
            $duplicateData = $this->AgentIncentiveFileModel->where('agent_id',$data['agent_id'])->where('incentive_month',$data['incentive_month'])->where('file_type','incentive')->first();
            if(!empty($duplicateData)){
                return $this->respond(['status' => 'failed', 'code' => 200, 'data' => 'Duplicate Entry.'], 200);
            }

            // handle file uploads
            $incentiveFile   = $this->request->getFile('incentive_file_name');

            $incentiveFileName   = null;

            // incentive upload
            if ($incentiveFile && $incentiveFile->isValid()) {
                $uploadPath = WRITEPATH . 'uploads/agent/incentive_file/';
                if (!is_dir($uploadPath)) {
                    mkdir($uploadPath, 0777, true);
                }
                $incentiveFileName = time() . '_' . $incentiveFile->getRandomName();
                $incentiveFile->move($uploadPath, $incentiveFileName);
            }

            $insertData = [
                'agent_id'              => $data['agent_id'],
                'incentive_month'       => $data['incentive_month'],
                'incentive_file_name'   => $incentiveFileName,
                'file_type'             => 'incentive',
                'created_by'            => $data['created_by'] ?? null
            ];

            $this->AgentIncentiveFileModel->insert($insertData);

            return $this->respond(['status' => 'success', 'code' => 200, 'data' => []], 200);

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

    // Delete agent incentive file
    public function deleteAgentIncentiveFile()
    {
        try {

            $id = $this->request->getGet('id');

          
            // check if agent exists
            $file = $this->AgentIncentiveFileModel->where('file_type','incentive')->find((int)$id);
            if (!$file) {
                return $this->respond(['status' => 'failed','code'   => 200, 'data'   => 'File not found'], 200);
            }

            // update status
            $this->AgentIncentiveFileModel->update($id, ['is_active' => 0]);

            return $this->respond([
                'status'  => 'success', 'code'    => 200,'data'   => "File status updated"], 200);

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

    // Download agent incentive file
    public function downloadAgentIncentiveFile()
    {
        try {
            $id = $this->request->getGet('id');
            $type = $this->request->getGet('type'); // 'incentive' or 'grid'

            if (!$id) {
                return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'ID is required'], 200);
            }

            $fileType = (!empty($type) && $type === 'grid') ? 'grid' : 'incentive';
            // Fetch record from DB
            $fileRecord = $this->AgentIncentiveFileModel->where('is_active',1)->where('file_type',$fileType)->find((int)$id);

            if (!$fileRecord) {
                return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File not found'], 200);
            }

            $filePath = WRITEPATH . 'uploads/agent/incentive_file/' . $fileRecord['incentive_file_name'];

            if (!file_exists($filePath)) {
                return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File missing on server'], 200);
            }

            // Force file download
            return $this->response->download($filePath, null);

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

    //Empty Commit 

}
