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

trait TransAccProcess {

	public function processTransactionAcc($transId, $data, $isAccPmt = false)
	{
		if (!in_array($data['status'], $this->CI->config->item('ignore_status')) && !in_array($data['tType'], TransFlag::$NonAccTranTypes))
		{
			
			$this->handleTransAcc($transId, $data, $isAccPmt);
		}
		else if ($data['status'] != 'D' && in_array($data['tType'], [DELCHALLAN, PURRECP]))
		{
			$this->handleStockRelatedTrans($transId);
		}
	}

	private function handleTransAcc($transId, $data, $isAccPmt)
	{
		if (!in_array($data['tType'], [JOURNAL_VOUCHER, JOURNAL_CONTRA, PURORD, EXPRETAIL, SALPMT, PURPMT]) ||
			(in_array($data['tType'], [SALPMT, PURPMT]) && (empty($data['classCode']) || $data['classCode'] != 'XPNG')) ||
			($data['tType'] == EXPRETAIL && TransFlag::$items_insert))
		{
			if (!$this->CI->trans_acc_table->save($transId, $data))
			{
				throw new Exception($this->CI->trans_acc_table->error ?: $this->error);
				
			}
		}
		elseif (!empty($data['acc_details']) || TransFlag::$exp_acc_details)
		{
			$this->processAccountDetails($transId, $data, $isAccPmt);
		}

		$this->updateBalances($transId, $data);
	}

	private function processAccountDetails($transId, $data, $isAccPmt)
	{
		TransFlag::$exp_acc_details = !empty($data['acc_details']) ? $data['acc_details'] : TransFlag::$exp_acc_details;
		$detail_key = 0;

		foreach (TransFlag::$exp_acc_details as $key => $row) {
			$row = $this->prepareAccountRow($row, $transId, $isAccPmt, $data, $detail_key);
			$this->CI->db->insert('trans_acc', $row);
		}

		// $this->insertPayModes($transId, $data);
		// $this->insertTaxes($transId, $data);
	}

	private function clean_number($input)
	{
		return str_replace(',', '', preg_replace('/[^\d.,-]/', '', $input));
	}

	private function prepareAccountRow($row, $transId, $isAccPmt, $data, &$detail_key)
	{
		$row['cId'] = $this->cId;
		$row['transId'] = $transId;

		$row['debit'] = $this->clean_number($row['debit']);
		$row['credit'] = $this->clean_number($row['credit']);

		$row['debit'] = is_numeric($row['debit']) ? $row['debit'] : 0;
		$row['credit'] = is_numeric($row['credit']) ? $row['credit'] : 0;

		if ($isAccPmt) {
			$row = $this->swapDebitCredit($row);
		}

		$row['dueAmount'] = 0;

		$this->calculateDueAmountIfNeeded($row, $data, $transId);
		$this->handleBillableExpense($row, $data, $transId, $detail_key);

		$row = $this->strip_fields($row, $this->CI->trans_acc_table->list_fields());
		$row['debit'] = $row['debit'] ? $row['debit'] : 0;
		$row['credit'] = $row['credit'] ? $row['credit'] : 0;

		return $row;
	}
	private function swapDebitCredit($row)
	{
		$row['debit'] = $row['debit'] - $row['credit'];
		$row['credit'] = $row['credit'] + $row['debit'];
		$row['debit'] = $row['credit'] - $row['debit'];
		return $row;
	}

	private function calculateDueAmountIfNeeded(&$row, $data, $transId)
	{
		if (!empty($row['conId'])) {
			$this->CI->db->select('a.id,a.accCode');
			$this->CI->db->from('account as a');
			$this->CI->db->join('accountgroup as ag', 'ag.id=a.groupId');
			$this->CI->db->where(['a.cId' => $this->cId, 'a.id' => $row['accId']]);
			$this->CI->db->where_in('ag.acType', ['A', 'L']);

			if ($tmp = $this->CI->db->get()->row_array()) {
				$row['accCode'] = $row['accCode'] ? $row['accCode'] : $tmp['accCode'];
				$row['dueAmount'] = $row['debit'] - $row['credit'];

				if (!empty($row['allotAmt'])) {
					$row['dueAmount'] += $row['allotAmt'];
				}
			}

			if (!empty($row['id']) && in_array($data['tType'], [JOURNAL_VOUCHER, JOURNAL_CONTRA])) {
				$this->CI->db->select('ifnull(sum(allotAmt+tdsAmt+writeOff),0) as allotAmt');
				$this->CI->db->from('trans_payment');
				$this->CI->db->where([
					'cId' => $this->cId,
					'transId' => $transId,
					'allotTaId' => $row['id'],
					'allotConId' => $row['conId']
				]);

				if ($tmp = $this->CI->db->get()->row_array()) {
					if (abs($row['dueAmount']) < abs($tmp['allotAmt'])) {
						throw new Exception(sprintf(lang('ALLOTED_AMOUNT_MISMATCH'), $tmp['allotAmt']));
					}

					if (!empty($row['debit'])) {
						$row['dueAmount'] -= $tmp['allotAmt'];
					} else {
						$row['dueAmount'] += $tmp['allotAmt'];
					}
				}
			}
		}
	}

	private function handleBillableExpense($row, $data, $transId, &$detail_key)
	{
		if (!empty($row['prjconId']) && $data['tType'] == EXPRETAIL && $data['classCode'] == 'XPNG' && isset($data['details'][$detail_key])) {
			$tmp_item = $data['details'][$detail_key];
			$detail_key++;

			if (empty($tmp_item['itemId'])) {
				$tmp_item['transId'] = $transId;
				$tmp_item = $this->strip_fields($tmp_item, $this->trans_item_fields());
				$this->CI->db->insert('trans_items', $tmp_item);
				$tmp_transItemId = $this->CI->db->insert_id();

				if (empty($data['prjconId'])) {
					$this->CI->db->insert('trans_billable', [
						'cId' => $this->cId,
						'transItemId' => $tmp_transItemId,
						'prjconId' => $row['prjconId'],
						'invTransId' => 0,
						'transId' => $transId,
						'tsType' => $row['tsType']
					]);
				}
			}
		}
	}

	private function updateBalances($transId, $data)
	{
		if (!$this->CI->trans_acc_table->update_contact_balance($transId, false, "", !empty($data['paymentAccId']) ? $data['paymentAccId'] : null))
		{
			$this->error = $this->CI->trans_acc_table->error;
			throw new Exception($this->CI->trans_acc_table->error);
		}
		else
		{
			$this->CI->trans_acc_table->update_account_balance($transId, false);
		}
	}

	private function handleStockRelatedTrans($transId)
	{
		$this->CI->load->library('trans_acc_table');
		$this->CI->trans_acc_table->cal_serialno_stkqty($transId);
		$this->CI->trans_acc_table->cal_stkqty($transId);

		if ($curStk = $this->CI->trans_acc_table->is_negative_serial($transId)) {
			throw new Exception(sprintf(lang('SERILA_MISMATCH'), $curStk));
		}
	}

}

