<?php defined('BASEPATH') or exit('No direct script access allowed');

class Komplain extends CI_Controller
{
    private $types=['Kesalahan desain','Salah ukuran','Salah teks','Salah warna','Hasil cetak tidak sesuai','Cetakan blur','Cetakan belang','Register tidak pas','Bahan salah','Finishing rusak','Potong tidak presisi','Laminasi rusak','Jumlah kurang','Produk rusak','Salah kirim','Lainnya'];
    public function __construct(){parent::__construct();cek_session_login();$this->load->model('Komplain_model','komplain');if(!$this->komplain->installed())$this->fail('Modul belum dipasang. Jalankan db/complaint_management.sql.',503);}
    private function guard($permission,$menuFallback=false){if($this->komplain->can($permission)||($menuFallback&&$this->komplain->menuAllowed()))return;if($this->input->is_ajax_request())$this->fail('Anda tidak memiliki hak akses untuk tindakan ini.',403);redirect('error/403');}
    public function index(){$this->guard('complaint.view',true);$data=['title'=>'Manajemen Komplain | '.info()['title'],'summary'=>$this->komplain->summary(),'types'=>$this->types,'statuses'=>Komplain_model::STATUSES,'prefillInvoiceToken'=>trim((string)$this->input->get('invoice',true))];$this->template->load('main/themes','komplain/index',$data);}
    public function data($offset=0){$this->guard('complaint.view',true);if(!$this->input->is_ajax_request())show_404();$offset=max(0,(int)$offset);$limit=(int)$this->input->post('limit');if(!in_array($limit,[10,20,50,100],true))$limit=10;$f=[];foreach(['q','status','priority','complaint_type','root_cause_department','from','to'] as $key)$f[$key]=trim((string)$this->input->post($key,true));$total=$this->komplain->countRows($f);if($offset>=$total&&$total>0)$offset=(int)(floor(($total-1)/$limit)*$limit);$config=['target'=>'#complaintData','base_url'=>base_url('komplain/data'),'total_rows'=>$total,'per_page'=>$limit,'link_func'=>'loadComplaints'];$this->ajax_pagination->initialize($config);$this->load->view('komplain/_list',['rows'=>$this->komplain->rows($f,$limit,$offset),'total'=>$total,'offset'=>$offset],false);}
    public function search_order(){$this->guard('complaint.create',true);if(!$this->input->is_ajax_request())show_404();$q=trim((string)$this->input->get('q',true));$this->json(['rows'=>mb_strlen($q)<2?[]:$this->komplain->searchOrders($q)]);}
    public function order_items($id=0){$this->guard('complaint.create',true);if(!$this->input->is_ajax_request())show_404();$this->json(['rows'=>$this->komplain->orderItems((int)$id)]);}
    public function create($invoiceId=0){$this->guard('complaint.create',true);$invoiceId=(int)$invoiceId;if(!$invoiceId&&$this->input->get('invoice'))$invoiceId=(int)decrypt_url((string)$this->input->get('invoice'));$order=$invoiceId?$this->komplain->order($invoiceId):null;$items=$order?$this->komplain->orderItems($invoiceId):[];$this->template->load('main/themes','komplain/create',['title'=>'Buat Komplain | '.info()['title'],'order'=>$order,'items'=>$items,'types'=>$this->types]);}
    public function modal_form(){ $this->guard('complaint.create',true);if(!$this->input->is_ajax_request())show_404();$token=trim((string)$this->input->get('invoice',true));$invoiceId=$token!==''?(int)decrypt_url($token):0;$preselectedOrder=$invoiceId>0?$this->komplain->order($invoiceId):null;$this->load->view('komplain/_modal_form',['types'=>$this->types,'preselectedOrder'=>$preselectedOrder],false); }
    public function store()
    {
        $this->guard('complaint.create',true);$invoiceId=(int)$this->input->post('transaction_id');$order=$this->komplain->order($invoiceId);if(!$order)$this->fail('Transaksi tidak valid.',422);
        $all=array_column($this->komplain->orderItems($invoiceId),null,'id_rincianinvoice');$posted=$this->input->post('items');if(!is_array($posted)||!$posted)$this->fail('Pilih minimal satu item komplain.',422);$items=[];$sumOrder=0;$sumComplaint=0;$originalDetail=null;
        foreach($posted as $detailId=>$values){$detailId=(int)$detailId;if(!isset($all[$detailId])||!is_array($values))$this->fail('Item transaksi tidak valid.',422);$qty=$this->decimal($values['complaint_qty']??0);$orderQty=(float)$all[$detailId]['jumlah'];if($qty<=0||$qty>$orderQty)$this->fail('Qty bermasalah harus lebih dari 0 dan tidak boleh melebihi qty order.',422);$sumOrder+=$orderQty;$sumComplaint+=$qty;if($originalDetail===null)$originalDetail=$detailId;$items[]=['transaction_detail_id'=>$detailId,'product_id'=>(int)$all[$detailId]['id_produk'],'product_name'=>$all[$detailId]['product_name'],'order_qty'=>$orderQty,'complaint_qty'=>$qty,'rework_qty'=>0,'issue_description'=>trim((string)($values['issue_description']??''))];}
        $type=trim((string)$this->input->post('complaint_type',true));if(!in_array($type,$this->types,true))$this->fail('Jenis komplain tidak valid.',422);$description=trim((string)$this->input->post('description',true));if($description==='')$this->fail('Deskripsi komplain wajib diisi.',422);$date=$this->date($this->input->post('complaint_date'));if(!$date)$this->fail('Tanggal komplain tidak valid.',422);$priority=(string)$this->input->post('priority',true);if(!in_array($priority,['LOW','NORMAL','HIGH','URGENT'],true))$priority='NORMAL';
        $files=$this->uploads();$head=['transaction_id'=>$invoiceId,'customer_id'=>(int)$order['id_konsumen'],'original_spk_detail_id'=>$originalDetail,'complaint_date'=>$date,'complaint_type'=>$type,'description'=>$description,'customer_request'=>trim((string)$this->input->post('customer_request',true)),'internal_note'=>trim((string)$this->input->post('internal_note',true)),'order_qty'=>$sumOrder,'complaint_qty'=>$sumComplaint,'priority'=>$priority];$id=$this->komplain->createComplaint($head,$items,(int)$this->session->idu,$files);if(!$id){$this->removeUploads($files);$this->fail('Komplain gagal disimpan.',500);}$this->json(['status'=>200,'msg'=>'Komplain berhasil dibuat.','redirect'=>site_url('komplain/detail/'.$id)]);
    }
    public function detail($id=0){$this->guard('complaint.view',true);$row=$this->komplain->find($id);if(!$row)show_404();$extra=$this->komplain->detailData($id);$users=$this->db->select('id_user,nama_lengkap')->where('aktif','Y')->order_by('nama_lengkap')->get('tb_users')->result_array();$this->template->load('main/themes','komplain/detail',array_merge(['title'=>$row['complaint_no'].' | '.info()['title'],'row'=>$row,'users'=>$users,'processMap'=>$this->komplain->reworkProcessMap()],$extra));}
    public function decision($id=0){$row=$this->komplain->find($id);if(!$row)show_404();$decision=strtoupper((string)$this->input->post('decision',true));$perm=$decision==='REJECTED'?'complaint.reject':'complaint.approve';$this->guard($perm);if(!in_array($row['status'],['OPEN','VERIFICATION'],true))$this->fail('Status komplain tidak dapat diverifikasi.',422);$type=trim((string)$this->input->post('resolution_type',true));$note=trim((string)$this->input->post('resolution_note',true));if($decision==='REJECTED'&&$note==='')$this->fail('Alasan penolakan wajib diisi.',422);if(!in_array($decision,['VERIFICATION','APPROVED','REJECTED'],true))$this->fail('Keputusan tidak valid.',422);$data=['status'=>$decision,'resolution_type'=>$type,'resolution_note'=>$note,'root_cause_department'=>trim((string)$this->input->post('root_cause_department',true)),'root_cause_user_id'=>(int)$this->input->post('root_cause_user_id')?:null,'root_cause_category'=>trim((string)$this->input->post('root_cause_category',true)),'root_cause_note'=>trim((string)$this->input->post('root_cause_note',true))];if(in_array($decision,['APPROVED','REJECTED'],true)){$data['approved_by']=(int)$this->session->idu;$data['approved_at']=date('Y-m-d H:i:s');}$ok=$this->komplain->updateDecision($id,$data,(int)$this->session->idu);$this->respond($ok,'Keputusan berhasil disimpan.');}
    public function rework($id=0){$this->guard('complaint.rework');$row=$this->komplain->find($id);if(!$row)show_404();if(!in_array($row['status'],['APPROVED','REWORK','QC'],true))$this->fail('Rework hanya dapat dibuat untuk komplain yang disetujui.',422);$detail=(int)$this->input->post('detail_id');$item=$this->db->where(['complaint_id'=>(int)$id,'transaction_detail_id'=>$detail])->get('complaint_items')->row_array();if(!$item)$this->fail('Item rework tidak valid.',422);$qty=$this->decimal($this->input->post('qty'));$remaining=(float)$item['complaint_qty']-(float)$item['rework_qty'];if($qty<=0||$qty>$remaining)$this->fail('Qty rework melebihi sisa qty komplain.',422);$process=$this->input->post('process');$processMap=$this->komplain->reworkProcessMap();$process=is_array($process)?array_values(array_intersect(array_keys($processMap),$process)):[];if(!$process)$this->fail('Pilih minimal satu tahapan rework.',422);$detailRow=$this->db->where('id_rincianinvoice',$detail)->get('invoice_detail')->row_array();$rw=$this->komplain->createRework($row,['detail_id'=>$detail,'qty'=>$qty,'original_spk'=>$detailRow['no_spk']?:('SPK-'.$detail)],$process,(int)$this->session->idu);$this->respond((bool)$rw,'Rework dan SPK rework berhasil dibuat.');}
    public function process($id=0){$this->guard('complaint.rework');$row=$this->komplain->find($id);if(!$row)show_404();$status=strtoupper((string)$this->input->post('status',true));if(!in_array($status,['PENDING','IN_PROGRESS','DONE','SKIPPED','CANCELLED'],true))$this->fail('Status proses tidak valid.',422);$ok=$this->komplain->updateProcess($id,(int)$this->input->post('process_id'),$status,(int)$this->input->post('assigned_to'),trim((string)$this->input->post('notes',true)),(int)$this->session->idu);$this->respond($ok,'Progress rework diperbarui.');}
    public function cost($id=0){$this->guard('complaint.cost');$row=$this->komplain->find($id);if(!$row)show_404();$reworkId=(int)$this->input->post('rework_id');if(!$this->db->where(['id'=>$reworkId,'complaint_id'=>$id])->count_all_results('complaint_reworks'))$this->fail('Rework tidak valid.',422);$qty=$this->decimal($this->input->post('qty'));$unitCost=$this->decimal($this->input->post('unit_cost'));$type=trim((string)$this->input->post('cost_type',true));$allowed=['Material','Plate','Ink','Printing','Lamination','Cutting','Die Cut','Finishing','Labor','Delivery','Other'];if(!in_array($type,$allowed,true)||$qty<=0||$unitCost<0)$this->fail('Data biaya tidak valid.',422);$ok=$this->komplain->addCost($id,['rework_id'=>$reworkId,'cost_type'=>$type,'description'=>trim((string)$this->input->post('description',true)),'qty'=>$qty,'unit'=>substr(trim((string)$this->input->post('unit',true)),0,30),'unit_cost'=>$unitCost,'total_cost'=>$qty*$unitCost],(int)$this->session->idu);$this->respond($ok,'Biaya rework ditambahkan.');}
    private function uploads()
    {
        if (empty($_FILES['evidence']['name'][0])) return [];
        $out=[];$dir=FCPATH.'uploads/complaints/';
        if(!is_dir($dir)&&!mkdir($dir,0755,true))$this->fail('Folder upload tidak tersedia.',500);
        $allowed=['image/jpeg','image/png','image/webp','application/pdf'];
        $finfo=new finfo(FILEINFO_MIME_TYPE);
        foreach($_FILES['evidence']['tmp_name'] as $i=>$tmp){
            if($_FILES['evidence']['error'][$i]!==UPLOAD_ERR_OK)$this->fail('Upload bukti gagal.',422);
            if($_FILES['evidence']['size'][$i]>5*1024*1024)$this->fail('Ukuran bukti maksimal 5 MB.',422);
            $mime=$finfo->file($tmp);
            if(!in_array($mime,$allowed,true))$this->fail('Format bukti tidak diizinkan.',422);
            $baseName=bin2hex(random_bytes(16));
            if($mime==='application/pdf'){
                $name=$baseName.'.pdf';
                if(!move_uploaded_file($tmp,$dir.$name))$this->fail('Bukti gagal disimpan.',500);
                $storedMime='application/pdf';
            }else{
                if(!function_exists('imagewebp'))$this->fail('Server belum mendukung konversi gambar WebP.',500);
                $name=$baseName.'.webp';
                if(!$this->convertComplaintImageToWebp($tmp,$dir.$name))$this->fail('Gambar gagal dikonversi ke WebP.',422);
                $storedMime='image/webp';
            }
            $storedSize=is_file($dir.$name)?(int)filesize($dir.$name):0;
            $out[]=['file_name'=>$name,'original_name'=>substr(basename($_FILES['evidence']['name'][$i]),0,190),'file_path'=>'uploads/complaints/'.$name,'file_type'=>$storedMime,'file_size'=>$storedSize];
        }
        return $out;
    }

    private function convertComplaintImageToWebp($sourcePath,$destinationPath)
    {
        $info=@getimagesize($sourcePath);
        if(!$info||empty($info[0])||empty($info[1])||((int)$info[0]*(int)$info[1])>40000000)return false;
        $binary=@file_get_contents($sourcePath);if($binary===false)return false;
        $source=@imagecreatefromstring($binary);unset($binary);if(!$source)return false;
        $width=imagesx($source);$height=imagesy($source);$maxDimension=2400;
        $scale=min(1,$maxDimension/max($width,$height));$targetWidth=max(1,(int)round($width*$scale));$targetHeight=max(1,(int)round($height*$scale));
        $target=imagecreatetruecolor($targetWidth,$targetHeight);
        if(!$target){imagedestroy($source);return false;}
        imagealphablending($target,false);imagesavealpha($target,true);$transparent=imagecolorallocatealpha($target,0,0,0,127);imagefilledrectangle($target,0,0,$targetWidth,$targetHeight,$transparent);
        $resampled=imagecopyresampled($target,$source,0,0,0,0,$targetWidth,$targetHeight,$width,$height);
        $saved=$resampled&&@imagewebp($target,$destinationPath,82);
        imagedestroy($target);imagedestroy($source);
        if(!$saved&&is_file($destinationPath))@unlink($destinationPath);
        return $saved&&is_file($destinationPath)&&filesize($destinationPath)>0;
    }
    private function removeUploads($files){foreach($files as $f){$p=FCPATH.$f['file_path'];if(is_file($p))@unlink($p);}}
    private function decimal($v){return (float)str_replace(',','.',preg_replace('/[^0-9,.-]/','',(string)$v));}private function date($v){$v=trim((string)$v);$d=DateTime::createFromFormat('Y-m-d',$v);return $d&&$d->format('Y-m-d')===$v?$v:null;}
    private function respond($ok,$msg){$ok?$this->json(['status'=>200,'msg'=>$msg]):$this->fail('Operasi gagal disimpan.',500);}private function json($d,$c=200){$this->output->set_status_header($c)->set_content_type('application/json')->set_output(json_encode($d));}private function fail($m,$c){$this->json(['status'=>$c,'msg'=>$m],$c);exit;}
}
