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

class Chat_model extends CI_Model
{
	private $onlineSeconds = 90;

	public function ensureSchema()
	{
		if (!$this->db->table_exists('chat_messages')) {
			$this->db->query("CREATE TABLE `chat_messages` (`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,`sender_id` INT NOT NULL,`receiver_id` INT NOT NULL,`message` TEXT NOT NULL,`attachment_path` VARCHAR(255) NULL,`attachment_name` VARCHAR(255) NULL,`attachment_mime` VARCHAR(100) NULL,`attachment_size` INT UNSIGNED NULL,`attachment_type` ENUM('image','file') NULL,`created_at` DATETIME NOT NULL,`delivered_at` DATETIME NULL,`read_at` DATETIME NULL,PRIMARY KEY (`id`),KEY `idx_chat_sender_receiver_id` (`sender_id`,`receiver_id`,`id`),KEY `idx_chat_receiver_read` (`receiver_id`,`read_at`,`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
		}
		$columns = array(
			'attachment_path' => "VARCHAR(255) NULL AFTER `message`",
			'attachment_name' => "VARCHAR(255) NULL AFTER `attachment_path`",
			'attachment_mime' => "VARCHAR(100) NULL AFTER `attachment_name`",
			'attachment_size' => "INT UNSIGNED NULL AFTER `attachment_mime`",
			'attachment_type' => "ENUM('image','file') NULL AFTER `attachment_size`"
		);
		foreach ($columns as $name => $definition) {
			if (!$this->db->field_exists($name, 'chat_messages')) $this->db->query("ALTER TABLE `chat_messages` ADD `{$name}` {$definition}");
		}
		if (!$this->db->table_exists('chat_typing')) {
			$this->db->query("CREATE TABLE `chat_typing` (`user_id` INT NOT NULL,`receiver_id` INT NOT NULL,`expires_at` DATETIME NOT NULL,PRIMARY KEY (`user_id`,`receiver_id`),KEY `idx_chat_typing_receiver` (`receiver_id`,`expires_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
		}
	}

	public function allowedUserIds($currentId)
	{
		$rows = $this->db->select('id_user,parent')->where('aktif', 'Y')->get('tb_users')->result_array();
		$allowed = array((int)$currentId => TRUE);
		do {
			$changed = FALSE;
			foreach ($rows as $row) {
				$id = (int)$row['id_user']; $parent = (int)$row['parent'];
				if (isset($allowed[$id]) || ($parent > 0 && isset($allowed[$parent]))) {
					if (!isset($allowed[$id])) { $allowed[$id] = TRUE; $changed = TRUE; }
					if ($parent > 0 && !isset($allowed[$parent])) { $allowed[$parent] = TRUE; $changed = TRUE; }
				}
			}
		} while ($changed);
		return array_keys($allowed);
	}

	public function users($currentId)
	{
		$ids = $this->allowedUserIds($currentId);
		$this->db->select("u.id_user,u.nama_lengkap,u.level,u.foto,MAX(a.last_activity) last_activity", FALSE)
			->from('tb_users u')->join('user_agent a', 'a.id_user=u.id_user', 'left')
			->where('u.aktif', 'Y')->where_in('u.id_user', $ids)->where('u.id_user !=', $currentId)
			->group_by(array('u.id_user','u.nama_lengkap','u.level','u.foto'))->order_by('u.nama_lengkap', 'ASC');
		$users = $this->db->get()->result_array();
		foreach ($users as &$user) {
			$user['id'] = (int)$user['id_user']; unset($user['id_user']);
			$user['online'] = $user['last_activity'] && strtotime($user['last_activity']) >= time() - $this->onlineSeconds;
			$user['unread'] = (int)$this->db->where(array('sender_id'=>$user['id'],'receiver_id'=>$currentId,'read_at'=>NULL))->count_all_results('chat_messages');
		}
		return $users;
	}

	public function isAllowed($currentId, $otherId)
	{
		return $otherId > 0 && $otherId !== $currentId && in_array($otherId, $this->allowedUserIds($currentId), TRUE);
	}

	public function messages($currentId, $otherId, $afterId = 0)
	{
		$this->db->where("((sender_id=".(int)$currentId." AND receiver_id=".(int)$otherId.") OR (sender_id=".(int)$otherId." AND receiver_id=".(int)$currentId."))", NULL, FALSE);
		if ($afterId > 0) $this->db->where('id >', $afterId);
		if ($afterId > 0) {
			$rows = $this->db->order_by('id', 'ASC')->limit(100)->get('chat_messages')->result_array();
		} else {
			$rows = array_reverse($this->db->order_by('id', 'DESC')->limit(60)->get('chat_messages')->result_array());
		}
		foreach ($rows as &$row) {
			$row['id'] = (int)$row['id']; $row['sender_id'] = (int)$row['sender_id']; $row['receiver_id'] = (int)$row['receiver_id'];
		}
		return $rows;
	}

	public function markDelivered($currentId)
	{
		$this->db->where('receiver_id', $currentId)->where('delivered_at IS NULL', NULL, FALSE)->set('delivered_at', date('Y-m-d H:i:s'))->update('chat_messages');
	}

	public function markRead($currentId, $otherId)
	{
		$now = date('Y-m-d H:i:s');
		$this->db->where(array('sender_id'=>$otherId,'receiver_id'=>$currentId))->where('read_at IS NULL', NULL, FALSE)->set('delivered_at', $now)->set('read_at', $now)->update('chat_messages');
	}

	public function receipts($currentId, $otherId)
	{
		$rows = $this->db->select('id,delivered_at,read_at')->where(array('sender_id'=>$currentId,'receiver_id'=>$otherId))->order_by('id','DESC')->limit(100)->get('chat_messages')->result_array();
		foreach ($rows as &$row) $row['id'] = (int)$row['id'];
		return $rows;
	}

	public function typing($currentId, $otherId, $active)
	{
		if (!$active) { $this->db->delete('chat_typing', array('user_id'=>$currentId,'receiver_id'=>$otherId)); return; }
		$sql = "INSERT INTO chat_typing (user_id,receiver_id,expires_at) VALUES (?,?,?) ON DUPLICATE KEY UPDATE expires_at=VALUES(expires_at)";
		$this->db->query($sql, array($currentId, $otherId, date('Y-m-d H:i:s', time()+5)));
	}

	public function isTyping($currentId, $otherId)
	{
		return $this->db->where(array('user_id'=>$otherId,'receiver_id'=>$currentId))->where('expires_at >=', date('Y-m-d H:i:s'))->count_all_results('chat_typing') > 0;
	}
}
