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


class UserModel extends CI_Model
{


	public function __construct()
	{
		parent::__construct();
		$this->load->database();
		$this->load->library('encryption');
	}

	/**
	 * create_user function.
	 * 
	 * @access public
	 * @param mixed $username
	 * @param mixed $email
	 * @param mixed $password
	 * @return bool true on success, false on failure
	 */


	public function regUserTemp($data, $tableName)
	{
		// Validate and sanitize the input data
		$name = $this->security->xss_clean($data['name']);
		$email = $this->security->xss_clean($data['email']);
		$phone = $this->security->xss_clean($data['phone']);
		$state = $this->security->xss_clean($data['state']);
		$loan_amount = $this->security->xss_clean($data['loan_amount']);
		$source = isset($data['source']) ? $this->security->xss_clean($data['source']) : null;
		$act_date_time = $this->security->xss_clean($data['act_date_time']);

		// Rebuild sanitized insertData array
		$insertData = array(
			'name' => $name,
			'email' => $email,
			'phone' => $phone,
			'state' => $state,
			'act_date_time' => $act_date_time,
			'fip_id' => generateCustId(),
			'service' => $data["service"],
			'landing_url' => $data["landing_url"],
			'ip' => getClientIp()
		);

		if ($source) {
			$insertData['source'] = $source;
		}

		if ($loan_amount != "") {
			$insertData['loan_amount'] = $loan_amount;
		}

		// Check if phone already exists in the table using Active Record
		$this->db->where('phone', $phone);
		$query = $this->db->get($tableName);

		// If phone exists, return true to avoid duplicate entry
		if ($query->num_rows() > 0) {
			return true;
		}

		// Insert the sanitized data into the database securely
		$this->db->insert($tableName, $insertData);
		$insert_id = $this->db->insert_id(); // Get the last inserted ID

		// Return the inserted ID if successful, else return false
		return $insert_id ? $insert_id : false;
	}

	public function commonInsert($tableName, $insertData)
	{
		// Insert data into the table
		$this->db->insert($tableName, $insertData);

		// Check if the insert was successful
		if ($this->db->affected_rows() > 0) {
			// Return the last inserted ID
			return $this->db->insert_id();
		} else {
			// Insert failed, return false
			return false;
		}
	}

	public function phoneMailNumValidation($phoneNumber, $encrypted_phone_number, $fstep)
	{
		$curDate = date('Y-m-d H:i:s');
		$uid = '';

		// Check if the phone number is unique
		if ($this->is_phone_num_unique($phoneNumber)) {
			// Generate new user ID for a unique phone number
			$uid = $this->generateUserID();
			$dataFields = array(
				'u_id' => $uid,
				'phone' => $encrypted_phone_number,
				'u_status' => 'ST00',
				'reg_date' => $curDate
			);

			// Insert new user record
			$insertSuccess = $this->insertIntoUserApplicant($dataFields, "user_applicant", $phoneNumber);
			if (!$insertSuccess) {
				return array(
					'status' => false,
					'message' => 'Failed to register user.'
				);
			}
		} else {
			// Retrieve existing user ID for the phone number
			$uid = $this->get_u_id_by_phone($phoneNumber);
		}

		// Send OTP
		$otpSuccess = $this->sentOTP($uid, 'sms', $phoneNumber, '');

		// Check if OTP sending was successful
		if (!$otpSuccess) {
			return array(
				'status' => false,
				'message' => 'Failed to send OTP.'
			);
		}
		return array(
			'status' => true,
			'u_id' => $uid,
			'username' => $phoneNumber
		);
	}



	public function validateOtp($normal_phone, $otp)
	{
		// Check if phone number exists
		if ($this->is_phone_num_unique($normal_phone)) {
			return array(
				'status' => false,
				'message' => 'Phone number not found.'
			);
		}

		$hashphone = hash('sha256', $normal_phone);

		// Calculate the time two minutes ago
		$twoMinutesAgo = date('Y-m-d H:i:s', strtotime('-2 minutes'));
		$this->db->select('AU.otp_code, AU.u_id');
		$this->db->from('otp_auth AU');
		$this->db->join('phone_number_hash PNH', 'AU.u_id = PNH.u_id');
		$this->db->where('AU.otp_code', $otp);
		$this->db->where('AU.gen_datetime >=', $twoMinutesAgo);

		$query = $this->db->get();

		// Check if any rows are returned
		if ($query->num_rows() > 0) {
			$uid = $query->row()->u_id;
			$updateUserStatus = $this->db->query("UPDATE user_applicant SET u_status='ST01' WHERE u_id='$uid' ");
			return array(
				'status' => true,
				'u_id' => $uid,
				'phone' => $normal_phone
			);
		} else {
			return array(
				'status' => false,
				'message' => 'Invalid OTP or OTP has expired.'
			);
		}
	}


	public function InsertEmail($normal_email, $u_idnormal, $fullname)
	{
		$emailenc = $this->encryption->encrypt($normal_email);
		$cur_date = date('Y-m-d H:i:s');

		$q1 = $this->db->query("UPDATE user_applicant SET email='$emailenc',full_name='$fullname',update_date='$cur_date',u_status='ST05' WHERE u_id='$u_idnormal' ");
		if ($q1) {
			return true;
		} else {
			return false;
		}
	}

	public function getUserStatus($u_id_normal)
	{
		// Use Query Builder to fetch data
		$this->db->select('ua.u_status, us.status_description');
		$this->db->from('user_applicant ua');
		$this->db->join('user_status us', 'ua.u_status = us.status_code');
		$this->db->where('ua.u_id', $u_id_normal);

		$query = $this->db->get();

		if ($query->num_rows() > 0) {
			$row = $query->row();
			$resarr = array(
				'status' => true,
				'status_code' => $row->u_status,
				'message' => $row->status_description
			);
		} else {
			$resarr = array(
				'status' => false,
				'status_code' => null,
				'message' => 'No status found'
			);
		}

		return $resarr;
	}


	public function checkAadhaarExists($adhaarNo)
	{
		$this->db->where('adhaar_no', $adhaarNo);
		$query = $this->db->get('user_adhaar_info'); // Replace with your actual table name
		// Return true if the number exists, false otherwise
		return $query->num_rows() > 0;
	}



	// Internal Function For Usage
	private function insert_phone_hash($u_id, $phone_number)
	{
		$data = array(
			'u_id' => $u_id,
			'hash_phone' => hash('sha256', $phone_number),
			'gen_date_time' => date('Y-m-d H:i:s')
		);
		return $this->db->insert('phone_number_hash', $data);
	}

	private function get_u_id_by_phone($phone_number)
	{
		// Hash the phone number
		$phone_hash = hash('sha256', $phone_number);
		// Query the user_applicant table to find the matching phone hash
		$this->db->select('u_id');
		$this->db->from('phone_number_hash');
		$this->db->where('hash_phone', $phone_hash);
		$query = $this->db->get();

		// Check if a result is found and return the u_id
		if ($query->num_rows() > 0) {
			return $query->row()->u_id;
		} else {
			return null; // Phone number not found
		}
	}

	/* This function Sents OTP in both the chaannel SMS and Email */
	private function sentOTP($uid, $channel, $phone_norm, $email)
	{
		$twoMinutesAgo = date('Y-m-d H:i:s', strtotime('-2 minutes'));
		$check_existingotp = $this->db->query("SELECT otp_code FROM otp_auth WHERE u_id='$uid' AND gen_datetime>='$twoMinutesAgo'");
		if ($check_existingotp->num_rows()) {
			$OTP = $check_existingotp->row()->otp_code;
		} else {
			$OTP = $this->generateOTP($uid, $channel, $email);
		}
		$std_name = 'User test';
		$new_std_id = $OTP;

		$content = "Dear " . $std_name . ", Thank you for showing interest in Spoken English Course at FastInfo Class. Your application ID is " . $new_std_id . ". Please make the payment - https://www.fastinfoclass.com/check-out?sid=" . $new_std_id . ". Best wishes, Team FastInfo Class";

		$msg1 = urlencode($content);
		$ch = curl_init();
		$temp_id = '1107164249094172037';
		$url = "http://smsgw.tatatel.co.in:9507/campaignService/campaigns/qs?recipient=" . $phone_norm . "&dr=false&msg=" . $msg1 . "&user=FASTIN01&pswd=Fasti^01&sender=FASTIN&PE_ID=1101473880000040876&Template_ID=" . $temp_id . "";
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_exec($ch);


		return true;
	}

	public function insertIntoUserApplicant($data, $table, $normalphone)
	{
		$this->db->trans_start(); // Begin transaction
		// Insert the data into the table
		$this->db->insert($table, $data);
		// Check if the insert was successful
		if ($this->db->affected_rows() > 0) {
			$this->db->trans_complete(); // Complete the transaction
			$this->insert_phone_hash($data['u_id'], $normalphone);
			return true;
		} else {
			$this->db->trans_rollback(); // Rollback the transaction if failed
			return false;
		}
	}


	private function generateOTP($uid, $channel, $mail_or_phone_addr)
	{
		$otp = mt_rand(100000, 999999);
		$currentDateTime = date('Y-m-d H:i:s');

		// Use transactions for atomic operation
		$this->db->trans_start();

		$this->db->where('u_id', $uid)
			->where('gen_datetime >', $currentDateTime)
			->delete('otp_auth');

		$this->db->insert('otp_auth', [
			'u_id' => $uid,
			'otp_code' => $otp,
			'gen_datetime' => $currentDateTime
		]);

		$this->db->trans_complete();

		return $this->db->trans_status() ? $otp : false;
	}


	private function generateUserID()
	{
		$prefix = 'UD';
		$length = 10;  // Total length of the u_id including the prefix
		$timeStr = str_replace('.', '', microtime(true));  // Get a microtime string

		// Ensure the length is fixed by truncating or padding the time string
		$u_id = $prefix . substr($timeStr, - ($length - strlen($prefix)));

		// Check if the generated u_id is unique in the database
		if ($this->is_u_id_unique($u_id)) {
			return $u_id;
		} else {
			// If not unique, generate again (recursive call)
			return $this->generate_unique_u_id();
		}
	}

	private function is_u_id_unique($u_id)
	{
		// Check against the 'user_applicant' table for uniqueness
		$this->db->where('u_id', $u_id);
		$query = $this->db->get('user_applicant');
		return $query->num_rows() == 0;
	}

	private function is_phone_num_unique($phone_number)
	{
		$phone_hash = hash('sha256', $phone_number);
		$this->db->where('hash_phone', $phone_hash);
		$query = $this->db->get('phone_number_hash');
		return $query->num_rows() == 0;
	}

	public function validateUID($u_id)
	{
		$qcheck = $this->db->query("SELECT u_id FROM user_applicant WHERE u_id='$u_id'  ");
		if ($qcheck->num_rows()) {
			return true;
		} else {
			return false;
		}
	}


	public function previewAdhaardetailsIfExists($adhaarNo, $uId)
	{
		$where = "";
		if ($adhaarNo == "") {
			$where = "u_id='$uId'";
		} else {
			$where = "u_id='$uId' ";
		}
		$isExistsq = $this->db->query("SELECT * FROM user_adhaar_info WHERE u_id='$uId' ");

		if ($isExistsq->num_rows()) {
			$rowData = $isExistsq->row();
			$fullName = $this->encryption->decrypt($rowData->full_name);
			$careOf = $this->encryption->decrypt($rowData->care_of);
			$adharNumber = $this->maskNumber($this->encryption->decrypt($rowData->adhaar_no));
			$gender = $this->encryption->decrypt($rowData->gender);
			if ($gender == 'M') {
				$gender = "Male";
			} else if ($gender == 'F') {
				$gender = "Female";
			}
			return array(
				"status" => true,
				"message" => "Adhaar Details Present",
				"data" => array(
					"adhaar_no" => $adharNumber,
					"full_name" => $fullName,
					"care_of" => $careOf,
					"gender" => $gender
				)
			);
		} else {
			return array(
				"status" => false,
				"message" => "No Adhaar data Present"
			);
		}
	}

	public function insertAdhaarData($table, $data)
	{
		if (is_array($data) && !empty($data)) {
			$u_id = $data['u_id'];
			$adhaar_no = $this->encryption->decrypt($data['adhaar_no']);
			// Update the 'user_applicant' table
			$this->db->where('u_id', $u_id);
			$this->db->update("user_applicant", array('u_status' => 'ST02', 'adhaar_no' => $adhaar_no));
			// Insert the data into the specified table
			return $this->db->insert($table, $data);
		}
		return false;
	}

	public function updatePanData($table, $data)
	{
		if (is_array($data) && !empty($data)) {
			$u_id = $data['u_id'];
			$pan_no = $this->encryption->encrypt($data['pan_no']);
			// Update the 'user_applicant' table
			$this->db->where('u_id', $u_id);
			$this->db->update("user_applicant", array('u_status' => 'ST03', 'pan_no' => $pan_no));
			// Insert the data into the specified table
			return $this->db->insert($table, $data);
		}
		return false;
	}

	public function getPanNoByUid($u_id)
	{
		$this->db->select('pan_no');
		$this->db->from('user_pan_info');
		$this->db->where('u_id', $u_id);
		$query = $this->db->get();

		if ($query->num_rows() > 0) {
			return array(
				'status' => true,
				'pan_no' => $this->encryption->decrypt($query->row()->pan_no)
			);
		} else {
			return array(
				'status' => false
			);
		}
	}

	public function InsertBankInfo($tableName, $data)
	{
		return $this->db->insert($tableName, $data);
	}

	public function matchUserInfo($UserName, $u_id)
	{
		$this->db->select('adhaar_no');
		$this->db->from('user_adhaar_info');
		$this->db->where('u_id', $u_id);
		$query = $this->db->get();
		if ($query->num_rows() > 0) {
			$adhar_no = $this->encryption->decrypt($query->row()->adhaar_no);
			return strtolower($adhar_no) == strtolower($UserName);
		}
		return false;
	}

	public function checkInsertDevId($uid, $devid)
	{
		// Check if the device_id already exists for the given u_id
		$this->db->where('u_id', $uid);
		$this->db->where('device_id', $devid);
		$query = $this->db->get('user_applicant');

		if ($query->num_rows() > 0) {
			return true;
		} else {
			// Update or insert the device_id
			$data = array('device_id' => $devid);
			$this->db->where('u_id', $uid);
			$this->db->update('user_applicant', $data);
			return true;
		}
	}


	private function maskNumber($number)
	{
		$numberStr = (string) $number;
		return str_repeat('*', max(0, strlen($numberStr) - 4)) . substr($numberStr, -4);
	}

	private function generateLoanId()
	{
		$microtime = microtime(true);
		$milliseconds = sprintf("%03d", ($microtime - floor($microtime)) * 1000); // Extract milliseconds
		$uniquePart = date('ymdHis') . $milliseconds; // Format: ymdHis + milliseconds

		// Prefix the loan ID with 'LD'
		$loanId = 'LD' . $uniquePart;

		while ($this->isLoanIdExists($loanId)) {
			// If the ID already exists, regenerate the unique part with a new timestamp and random number
			$microtime = microtime(true);
			$milliseconds = sprintf("%03d", ($microtime - floor($microtime)) * 1000);
			$uniquePart = date('ymdHis') . $milliseconds;
			$loanId = 'LD' . $uniquePart;
		}

		return $loanId;
	}

	private function isLoanIdExists($loanId)
	{
		$this->db->where('loan_id', $loanId);
		$query = $this->db->get('loans'); // Assuming 'loans' is the name of your table
		return $query->num_rows() > 0;
	}
}
