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

class Chat extends CI_Controller
{
	private $userId;
	private $maxAttachmentBytes = 10485760;
	public function __construct()
	{
		parent::__construct();
		cek_session_login();
		$settings = info();
		if (isset($settings['chat_aktif']) && (int)$settings['chat_aktif'] !== 1) {
			$this->output->set_status_header(403)->set_content_type('application/json','utf-8')->set_output(json_encode(array('status'=>403,'chat_enabled'=>FALSE,'message'=>'Fitur chat sedang dinonaktifkan')))->_display();
			exit;
		}
		$this->userId = (int)$this->session->idu;
		$this->load->model('Chat_model', 'chat');
		$this->chat->ensureSchema();
	}

	private function json($data, $status = 200)
	{
		return $this->output->set_status_header($status)->set_content_type('application/json','utf-8')->set_output(json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
	}
	private function postOnly() { if ($this->input->method(TRUE) !== 'POST') { $this->json(array('status'=>405,'message'=>'Metode tidak diizinkan'),405); return FALSE; } return TRUE; }
	private function otherUser() { $id=(int)$this->input->post('user_id',TRUE); return $this->chat->isAllowed($this->userId,$id) ? $id : 0; }

	public function users()
	{
		if (!$this->postOnly()) return;
		$this->chat->markDelivered($this->userId);
		$users=$this->chat->users($this->userId); $total=0;
		foreach($users as &$u) {
			$total += (int)$u['unread'];
			$photoPath = !empty($u['foto']) ? ltrim(str_replace('\\', '/', $u['foto']), '/') : '';
			$u['photo_url'] = ($photoPath !== '' && is_file(FCPATH.$photoPath)) ? base_url($photoPath) : '';
			unset($u['foto']);
		}
		unset($u);
		$this->json(array('status'=>200,'users'=>$users,'unread_total'=>$total,'server_time'=>date('Y-m-d H:i:s')));
	}
	public function messages()
	{
		if (!$this->postOnly()) return; $other=$this->otherUser(); if (!$other) { $this->json(array('status'=>403,'message'=>'Pengguna tidak tersedia'),403); return; }
		$markRead=(int)$this->input->post('mark_read',TRUE)===1; if($markRead)$this->chat->markRead($this->userId,$other);
		$this->chat->markDelivered($this->userId);
		$this->json(array('status'=>200,'messages'=>$this->chat->messages($this->userId,$other,(int)$this->input->post('after_id',TRUE)),'receipts'=>$this->chat->receipts($this->userId,$other),'typing'=>$this->chat->isTyping($this->userId,$other)));
	}
	public function send()
	{
		if (!$this->postOnly()) return; $other=$this->otherUser(); if (!$other) { $this->json(array('status'=>403,'message'=>'Pengguna tidak tersedia'),403); return; }
		$message=trim((string)$this->input->post('message',FALSE)); $message=preg_replace("/\r\n?|\n/", "\n", $message);
		if (mb_strlen($message,'UTF-8')>4000) { $this->json(array('status'=>422,'message'=>'Pesan maksimal 4000 karakter'),422); return; }
		$attachment = NULL;
		if (!empty($_FILES['attachment']) && $_FILES['attachment']['error'] !== UPLOAD_ERR_NO_FILE) {
			try { $attachment = $this->storeAttachment($_FILES['attachment']); }
			catch (Throwable $e) {
				log_message('error','Chat attachment: '.$e->getMessage());
				$messageError=$e instanceof RuntimeException ? $e->getMessage() : 'Lampiran gagal diproses';
				$this->json(array('status'=>422,'message'=>$messageError),422); return;
			}
		}
		if ($message==='' && !$attachment) { $this->json(array('status'=>422,'message'=>'Tulis pesan atau pilih lampiran'),422); return; }
		$data=array('sender_id'=>$this->userId,'receiver_id'=>$other,'message'=>$message,'created_at'=>date('Y-m-d H:i:s'));
		if ($attachment) $data=array_merge($data,$attachment);
		if (!$this->db->insert('chat_messages',$data)) { if($attachment) @unlink(FCPATH.$attachment['attachment_path']); $this->json(array('status'=>500,'message'=>'Pesan gagal disimpan'),500); return; }
		$id=(int)$this->db->insert_id(); $this->chat->typing($this->userId,$other,FALSE);
		$this->json(array('status'=>200,'message'=>$this->chat->messages($this->userId,$other,$id-1)[0]));
	}

	private function storeAttachment($file)
	{
		$uploadErrors=array(UPLOAD_ERR_INI_SIZE=>'Ukuran lampiran melebihi batas server',UPLOAD_ERR_FORM_SIZE=>'Ukuran lampiran terlalu besar',UPLOAD_ERR_PARTIAL=>'Upload lampiran terputus, silakan ulangi',UPLOAD_ERR_NO_TMP_DIR=>'Folder sementara server tidak tersedia',UPLOAD_ERR_CANT_WRITE=>'Server gagal menulis lampiran',UPLOAD_ERR_EXTENSION=>'Upload lampiran dihentikan oleh server');
		if ((int)$file['error'] !== UPLOAD_ERR_OK) throw new RuntimeException(isset($uploadErrors[(int)$file['error']])?$uploadErrors[(int)$file['error']]:'Upload lampiran gagal');
		if ((int)$file['size'] < 1 || (int)$file['size'] > $this->maxAttachmentBytes) throw new RuntimeException('Ukuran lampiran maksimal 10 MB');
		$finfo=new finfo(FILEINFO_MIME_TYPE); $mime=(string)$finfo->file($file['tmp_name']);
		$images=array('image/jpeg','image/png','image/gif','image/webp');
		$files=array('application/pdf'=>'pdf','application/msword'=>'doc','application/vnd.openxmlformats-officedocument.wordprocessingml.document'=>'docx','application/vnd.ms-excel'=>'xls','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'=>'xlsx','text/plain'=>'txt','text/csv'=>'csv','application/zip'=>'zip','application/x-rar-compressed'=>'rar','application/vnd.rar'=>'rar');
		$original=$this->cleanOriginalName($file['name']);
		$originalExtension=strtolower(pathinfo($original,PATHINFO_EXTENSION));
		if ($mime==='application/zip' && in_array($originalExtension,array('docx','xlsx'),TRUE)) $files[$mime]=$originalExtension;
		$directory='uploads/chat/'.date('Y/m').'/'; $absolute=FCPATH.$directory;
		if (!is_dir($absolute) && !mkdir($absolute,0755,TRUE) && !is_dir($absolute)) throw new RuntimeException('Folder lampiran tidak dapat dibuat');
		$token=date('YmdHis').'_'.bin2hex(random_bytes(8));
		if (in_array($mime,$images,TRUE)) {
			$relative=$directory.$token.'.webp'; $this->convertImageToWebp($file['tmp_name'],FCPATH.$relative);
			return array('attachment_path'=>$relative,'attachment_name'=>$original,'attachment_mime'=>'image/webp','attachment_size'=>filesize(FCPATH.$relative),'attachment_type'=>'image');
		}
		if (!isset($files[$mime])) throw new RuntimeException('Tipe lampiran tidak didukung');
		$relative=$directory.$token.'.'.$files[$mime];
		if (!move_uploaded_file($file['tmp_name'],FCPATH.$relative)) throw new RuntimeException('Lampiran gagal disimpan');
		return array('attachment_path'=>$relative,'attachment_name'=>$original,'attachment_mime'=>$mime,'attachment_size'=>filesize(FCPATH.$relative),'attachment_type'=>'file');
	}

	private function convertImageToWebp($source, $destination)
	{
		$dimensions=@getimagesize($source);
		if (!$dimensions || (int)$dimensions[0]*(int)$dimensions[1] > 40000000) throw new RuntimeException('Resolusi gambar terlalu besar');
		$raw=@file_get_contents($source); $image=$raw!==FALSE ? @imagecreatefromstring($raw) : FALSE;
		if (!$image) throw new RuntimeException('File gambar tidak valid');
		$width=imagesx($image); $height=imagesy($image); $max=1600;
		$scale=min(1,$max/max($width,$height)); $newWidth=max(1,(int)round($width*$scale)); $newHeight=max(1,(int)round($height*$scale));
		$canvas=imagecreatetruecolor($newWidth,$newHeight); imagealphablending($canvas,FALSE); imagesavealpha($canvas,TRUE); $transparent=imagecolorallocatealpha($canvas,0,0,0,127); imagefilledrectangle($canvas,0,0,$newWidth,$newHeight,$transparent);
		imagecopyresampled($canvas,$image,0,0,0,0,$newWidth,$newHeight,$width,$height); $ok=imagewebp($canvas,$destination,78); imagedestroy($canvas); imagedestroy($image);
		if (!$ok) { if(file_exists($destination)) @unlink($destination); throw new RuntimeException('Gambar gagal dikonversi ke WebP'); }
	}

	private function cleanOriginalName($name)
	{
		$name=preg_replace('~[\x00-\x1F\x7F/\\\\]+~u','_',basename((string)$name));
		return mb_substr($name?:'lampiran',0,200,'UTF-8');
	}
	public function typing()
	{
		if (!$this->postOnly()) return; $other=$this->otherUser(); if (!$other) { $this->json(array('status'=>403),403); return; }
		$this->chat->typing($this->userId,$other,(int)$this->input->post('active',TRUE)===1); $this->json(array('status'=>200));
	}
}
