<?php

namespace App\DAO;

use App\DAO\DAOResponse\DAOResponse;
use App\DAO\DAOResponse\DAOResponseInterface;
use App\DAO\Pagination\Pagination;
use App\Entities\ComandaFechamento\ComandaFechamento;
use App\Entities\Procedimento\Procedimento;
use App\Entities\ProcedimentoExame\ProcedimentoExame;
use App\Mappers\PagamentoMapper;
use App\Mappers\ProcedimentoMapper;
use App\Models\ComandaFechamentoModel;
use App\Models\ComandaLancamentoModel;
use App\Models\ComandaPagamentoModel;
use App\Models\ProcedimentoExameModel;
use App\Models\ProcedimentoModel;
use App\Services\LogService;
use App\Services\JWT\UsuarioLogado;
use App\Services\ServiceResponse\ServiceResponse;
use App\Services\ServiceResponse\ServiceResponseInterface;
use App\Utils\DateUtils;
use App\Utils\Collections\QueryFilterCollection;
use App\Utils\Collections\QueryOrderCollection;
use App\ViewModels\Pagamento\PagamentoComandaFechamentoRegistrationViewModel\PagamentoComandaFechamentoViewModel;
use App\ViewModels\Procedimento\ProcedimentoRegistrationViewModel\ProcedimentoRegistrationViewModel;
use App\ViewModels\Procedimento\ProcedimentoUpdateViewModel\ProcedimentoUpdateViewModel;
// use const False\MyClass\true;
use Exception;
use App\ViewModels\Pagamento\PagamentoComandaPagamentoRegistrationViewModel\PagamentoComandaPagamentoViewModel;
use App\ViewModels\Pagamento\PagamentoComandaFormaPagamentoRegistrationViewModel\FormaPagamentoCartaoViewModel;
use App\ViewModels\Pagamento\PagamentoComandaFormaPagamentoRegistrationViewModel\PagamentoComandaFormaPagamentoViewModel;
use App\ViewModels\Pagamento\PagamentoComandaFormaPagamentoRegistrationViewModel\FormaPagamentoDinheiroViewModel;
use App\Entities\Credito\CreditoCliente;
use App\Models\CreditoClienteModel;

class PagamentoDAO extends DAO {

	public function persistPagamentoComandaRegistrationVM(PagamentoComandaFechamentoViewModel $pagamento_fechamento_vm, array $pagamento_lancamento_vm,
			array $formaPagamento, array $pagamento_comanda_vm): DAOResponse {

		$dao_response = new DAOResponse();
		try {
			$this->db->transStart();
			$resp_verificacao = $this->verificarItensJaPagos( $pagamento_lancamento_vm );
			$size_itens_erros = count( $resp_verificacao ['lista_erros'] );
			if ($size_itens_erros > 0) {
				$dao_response->setStatus( DAOResponseInterface::DATABASE_CONNECTION_ERROR );
				$dao_response->setData( $resp_verificacao ['lista_erros'] );
				log_message( 'error', json_encode( $resp_verificacao ['lista_erros'] ) );
				return $dao_response;
			}
			$size_outros_erros = count( $resp_verificacao ['errors'] );
			if ($size_outros_erros > 0) {
				$dao_response->setStatus( DAOResponseInterface::DATABASE_CONNECTION_ERROR );
				$dao_response->setData( [ ] );
				log_message( 'error', json_encode( $resp_verificacao ['errors'] ) );
				return $dao_response;
			}

			$resp_comanda_fechamento = $this->persistComandaFechamento( $pagamento_fechamento_vm );

			if ($resp_comanda_fechamento ["error"] ["code"] != 0) {
				$dao_response->setStatus( DAOResponseInterface::DATABASE_CONNECTION_ERROR );
				$dao_response->setData( [ ] );
				$dao_response->setErrors( $resp_comanda_fechamento->error );
				log_message( 'error', json_encode( $resp_comanda_fechamento->error ) );
				return $dao_response;
			}

			$comdandaFechamento = $resp_comanda_fechamento ["obj"];

			$resp_comanda_lancamento = $this->persistComandaLancamento( $pagamento_lancamento_vm, $comdandaFechamento );
			if ($resp_comanda_lancamento ["nok"] > 0) {
				$dao_response->setStatus( DAOResponseInterface::DATABASE_CONNECTION_ERROR );
				$dao_response->setData( [ 
					$resp_comanda_lancamento ['lancamentos_erros']
				] );
				$dao_response->setErrors( $resp_comanda_lancamento->error );
				log_message( 'error', json_encode( $resp_comanda_lancamento->error ) );
				return $dao_response;
			}

			$resp_comanda_pagamento = $this->persistComandaPagamento( $pagamento_comanda_vm, $formaPagamento, $comdandaFechamento );

			if ($resp_comanda_pagamento ["nok"] > 0) {
				$dao_response->setStatus( DAOResponseInterface::DATABASE_CONNECTION_ERROR );
				$dao_response->setData( [ 
					$resp_comanda_pagamento ['pagamentos_erros']
				] );
				$dao_response->setErrors( $resp_comanda_pagamento->error );
				log_message( 'error', json_encode( $resp_comanda_pagamento->error ) );
				return $dao_response;
			}

			$resp_comandaitem_pago = $this->updateComandaItemToPago( $pagamento_lancamento_vm );
			if ($resp_comandaitem_pago ["nok"] > 0) {
				$dao_response->setStatus( DAOResponseInterface::DATABASE_CONNECTION_ERROR );
				$dao_response->setData( [ 
					$resp_comandaitem_pago ['pagamentos_erros']
				] );
				$dao_response->setErrors( $resp_comandaitem_pago->error );
				log_message( 'error', json_encode( $resp_comandaitem_pago->error ) );

				return $dao_response;
			}

			// $error = $this->db->error();
			// if ($error && $error ['code']) {
			// $status_persistence = $error ['code'];
			// $dao_response_errors = [ ];
			// if (strpos( $error ['message'], 'procedimento.descricao' ) !== false) {
			// $dao_response_errors ['descricao'] = 'Esse procedimento já existe';
			// }
			// if (strpos( $error ['message'], 'fk_procedimento_id_tipo_procedimento' ) !== false) {
			// $dao_response_errors ['id_tipo_procedimento'] = 'O tipo de procedimento não existe';
			// }
			// if (strpos( $error ['message'], 'fk_procedimento_criado_por' ) !== false) {
			// $dao_response_errors ['criado_por'] = 'Esse usuário não existe.';
			// }
			// $dao_response->setErrors( $dao_response_errors );
			// log_message( 'error', json_encode( $error ) );
			// } else {
			$status_persistence = DAOResponseInterface::SUCESS;

			$this->db->transComplete();
			// }
		} catch ( Exception $exception ) {
			log_message( 'error', json_encode( $this->db->error() ) );
			$status_persistence = DAOResponseInterface::DATABASE_CONNECTION_ERROR;
		}
		$this->db->close();
		$dao_response->setStatus( $status_persistence );
		if ($status_persistence === DAOResponseInterface::SUCESS) {
			$dao_response->setData( 
				[ 
					'erros_lancamentos' => $resp_comanda_lancamento ['lancamentos_erros'],
					'erros_pagamentos' => $resp_comanda_pagamento ['pagamentos_erros']
				] );
		}
		return $dao_response;

	}

	private function verificarItensJaPagos(array $pagamento_lancamento_vm): array {

		$lista = array ();
		$erro = array ();

		$sql = <<<SQL
			select count(*) total from comanda_lancamento where comanda_item_id =:item_id: 
		SQL;

		foreach ( $pagamento_lancamento_vm as $obj ) {
			$item = $obj->getComandaItemId();
			$binds = [ 
				'item_id' => $item
			];

			$conn = db_connect();
			$result = $conn->query( $sql, $binds )
				->getResultArray();
			$error = $conn->error();
			if ($error->code == 0) {
				$total = $result [0] ['total'];
				if ($total > 0) {
					array_push( $lista, $obj );
				}
			} else {
				array_push( $erro, $error );
			}
		}
		$resp = [ 
			'lista_erros' => $lista,
			'errors' => $erro
		];
		return $resp;

	}

	private function persistComandaFechamento(PagamentoComandaFechamentoViewModel $pagamento_fechamento_vm): array {

		$comanda_fechamento_model = new ComandaFechamentoModel();
		$comanda_fechamento_model = PagamentoMapper::getComandaFechamentoFromPagamentoComandaFechamentoRegistrationVM( $pagamento_fechamento_vm );

		$sql = <<<SQL
			insert into comanda_fechamento (comanda_id,tipo_fechamento,valor,criado_por,data_criacao,hora_criacao) 
			values
			(:id_comanda:,:fechamento_tipo:,:valor:, :criadopor:, :datacriacao:,:horacriacao:)
		SQL;
		$binds = [ 
			"id_comanda" => $comanda_fechamento_model->getComanda_id(),
			"fechamento_tipo" => $comanda_fechamento_model->getTipo_fechamento(),
			"valor" => $comanda_fechamento_model->getValor(),
			"criadopor" => $comanda_fechamento_model->getCriado_por(),
			"datacriacao" => $comanda_fechamento_model->getData_criacao(),
			"horacriacao" => $comanda_fechamento_model->getHora_criacao()
		];

		$conn = db_connect();
		$conn->query( $sql, $binds );
		$error = $conn->error();

		if ($error->code == 0) {
			$requisicaoId = $conn->insertID();
			$comanda_fechamento_model->setId( $requisicaoId );
		}
		// $conn->close();
		$resp = [ 
			"obj" => $comanda_fechamento_model,
			"error" => $error
		];
		return $resp;

	}

	private function persistComandaLancamento(array $pagamento_lancamento_vm, ComandaFechamento $comandaFechamento): array {

		$lista = array ();

		foreach ( $pagamento_lancamento_vm as $obj ) {
			$obj->setComandaFechamentoId( $comandaFechamento->getId() );
			$obj->setCriado_por( UsuarioLogado::getUsuarioId() );
			$obj->setDataCriacao( DateUtils::today() );
			$obj->setHoraCriacao( DateUtils::now_time() );
			array_push( $lista, $obj );
		}

		$lista_lancamentos = array ();
		$lista_erros = array ();
		foreach ( $lista as $obj ) {
			$objModel = new ComandaLancamentoModel();
			$objModel = PagamentoMapper::getComandaLancamantoFromPagamentoComandaLancamentoRegistrationVM( $obj );
			$sql = <<<SQL
				insert into comanda_lancamento
					(comanda_item_id,comanda_fechamento_id,criado_por,data_criacao,hora_criacao,extornado)
					values
					(:id_comanda_item:,:id_comdanda_fechamento:, :criadopor:, :datacriacao:,:horacriacao:,:extornado:)
				
			SQL;
			$binds = [ 
				"id_comanda_item" => $objModel->getComanda_item_id(),
				"id_comdanda_fechamento" => $objModel->getComanda_fechamento_id(),
				"criadopor" => $objModel->getCriado_por(),
				"datacriacao" => $objModel->getData_criacao(),
				"horacriacao" => $objModel->getHora_criacao(),
				"extornado" => $objModel->getExtornado()
			];

			$conn = db_connect();
			$conn->query( $sql, $binds );
			$error = $conn->error();
			if ($error->code == 0) {
				$lancamentoId = $conn->insertID();
				$objModel->setId( $lancamentoId );
				array_push( $lista_lancamentos, $objModel );
			} else {
				$err = $error;
				$err ["item"] = $objModel;
				array_push( $lista_erros, $err );
			}
			// $conn->close();
		}
		$resp = [ 
			"ok" => count( $lista_lancamentos ),
			"nok" => count( $lista_erros ),
			"lancamentos" => $lista_lancamentos,
			"error" => $error,
			"lancamentos_erros" => $lista_erros
		];
		return $resp;

	}

	private function persistComandaPagamento(array $pagamento_comanda_vm, array $formaPagamento, ComandaFechamento $comandaFechamento): array {

		$lista = array ();

		$i = 0;

		foreach ( $pagamento_comanda_vm as $obj ) {
			$forma = $formaPagamento [$i];

			$card = PagamentoMapper::getDefaultFormaPagamentoCartaoRegistartionfromForm();
			$pix = PagamentoMapper::getDefaultFormaPagamentoPixRegistartionfromForm();
			$boleto = PagamentoMapper::getDefaultFormaPagamentoBoletRegistartionfromForm();
			$dinheiro = PagamentoMapper::getDefaultFormaPagamentoDinheiroRegistartionfromForm();
			$creditocliente = [ ];

			switch (intval( $forma->getFormaId() )) {
				case FORMAPAGAMENTO_CARTAOCREDITO :
					$cartao = $forma->getCard();
					$card = FormaPagamentoCartaoViewModel::builder()->setTitular( $cartao->titular )
						->setBandeira( $cartao->bandeira )
						->setCodauth( $cartao->codauth )
						->setCvv( $cartao->cvv )
						->setDebcred( $cartao->debcred )
						->setAnoVal( $cartao->ano_val )
						->setMaquineta( $cartao->maquineta )
						->setMesVal( $cartao->mes_val )
						->setNumero( $cartao->numero )
						->build();

					// $cardcred = PagamentoMapper::getFormaPagamentoCartaoRegistartionfromForm( $cartao );

					break;

				case FORMAPAGAMENTO_CARTAODEBITO :
					$cartao = $forma->getCard();
					$card = FormaPagamentoCartaoViewModel::builder()->setTitular( $cartao->titular )
						->setBandeira( $cartao->bandeira )
						->setCodauth( $cartao->codauth )
						->setCvv( $cartao->cvv )
						->setDebcred( $cartao->debcred )
						->setAnoVal( $cartao->ano_val )
						->setMaquineta( $cartao->maquineta )
						->setMesVal( $cartao->mes_val )
						->setNumero( $cartao->numero )
						->build();
					// $cardDeb = PagamentoMapper::getFormaPagamentoCartaoRegistartionfromForm( $cartao );

					break;

				case FORMAPAGAMENTO_DINHEIRO :
					$dh = $forma->getDinheiro();
					$dinheiro = FormaPagamentoDinheiroViewModel::builder()->setValor( $dh->getValor() )
						->setTroco( $dh->getTroco() )
						->build();
					// $dinheiro = PagamentoMapper::getFormaPagamentoDinheiroRegistartionfromForm( $forma->getDinheiro() );
					break;

				case FORMAPAGAMENTO_PIX :
					$pix = PagamentoMapper::getFormaPagamentoPixRegistartionfromForm( $forma->getPix() );
					break;

				case FORMAPAGAMENTO_BOLETO :
					$boleto = PagamentoMapper::getFormaPagamentoBoletRegistartionfromForm( $forma->getBoleto() );

					break;

				case FORMAPAGAMENTO_CREDITOCLIENTE :
					$creditos = $forma->getCreditoCliente();
					for($y = 0; $y < count( $creditos ); $y++) {
						$item = PagamentoMapper::getFormaPagamentoCreditoClienteRegistartionfromForm( $creditos [$y] );
						array_push( $creditocliente, $item );
					}
					break;

				case FORMAPAGAMENTO_FILANTROPIA :

					break;

				case FORMAPAGAMENTO_SUSANIMAL :

					break;

				default :
					break;
			}

			$obj->setComandaFechamentoId( $comandaFechamento->getId() );
			$obj->setFormaPagamentoId( $forma->getFormaId() );
			$obj->setValor( $forma->getValor() ?? 0.00);
			$obj->setBandeira( $card->getBandeira() ?? '');
			$obj->setCodauth( $card->getCodauth() );
			$obj->setMaquineta( $card->getMaquineta() ?? 'N');
			$obj->setDbtcrd( $card->getDebcred() ?? '');
			$obj->setObservacao( $forma->getObservacao() ?? '');
			$obj->setDinheiro( $dinheiro->getValor() ?? 0.00);
			$obj->setTroco( $dinheiro->getTroco() ?? 0.00);
			$obj->setChavePix( $pix->getChave() ?? '');
			$obj->setCriado_por( UsuarioLogado::getUsuarioId() );
			$obj->setDataCriacao( DateUtils::today() );
			$obj->setHoraCriacao( DateUtils::now_time() );
			$obj->setCreditoCliente( $creditocliente );

			array_push( $lista, $obj );
			$i++;
		}

		$lista_pagamentos = array ();
		$lista_erros = array ();
		foreach ( $lista as $obj ) {
			$objModel = new ComandaPagamentoModel();
			$objModel = PagamentoMapper::getComandaPagamentoFromPagamentoComandaPagamentoRegistrationVM( $obj );

			$sql = <<<SQL
				insert into comanda_pagamento
					(comanda_fechamento_id,valor,forma_pagamento_id,dbtcrd,maquineta,
					bandeira,codauth,observacao, dinheiro,troco,chavepix,criado_por,data_criacao,hora_criacao)
					values
					(:id_comdanda_fechamento:,:valor:,:id_forma_pagamento:,:creddeb:,:maqui:,:band:, :authcod:, :obs:,
					 :din:,:trc:,:pix:, :criadopor:, :datacriacao:,:horacriacao:)
					 
			SQL;
			$binds = [ ];

			switch (intval( $objModel->getForma_pagamento_id() )) {
				case FORMAPAGAMENTO_CARTAOCREDITO :

					$binds = [ 
						"id_comdanda_fechamento" => $objModel->getComanda_fechamento_id(),
						"valor" => $objModel->getValor(),
						"id_forma_pagamento" => $objModel->getForma_pagamento_id(),
						"creddeb" => $objModel->getDbtcrd(),
						"maqui" => $objModel->getMaquineta(),
						"band" => $objModel->getBandeira(),
						"authcod" => $objModel->getCodauth(),
						"obs" => $objModel->getObservacao(),
						"din" => $objModel->getDinheiro(),
						"trc" => $objModel->getTroco(),
						"pix" => $objModel->getChavepix(),
						"criadopor" => $objModel->getCriado_por(),
						"datacriacao" => $objModel->getData_criacao(),
						"horacriacao" => $objModel->getHora_criacao()
					];

					break;
				case FORMAPAGAMENTO_CARTAODEBITO :

					$binds = [ 
						"id_comdanda_fechamento" => $objModel->getComanda_fechamento_id(),
						"valor" => $objModel->getValor(),
						"id_forma_pagamento" => $objModel->getForma_pagamento_id(),
						"creddeb" => $objModel->getDbtcrd(),
						"maqui" => $objModel->getMaquineta(),
						"band" => $objModel->getBandeira(),
						"authcod" => $objModel->getCodauth(),
						"obs" => $objModel->getObservacao(),
						"din" => $objModel->getDinheiro(),
						"trc" => $objModel->getTroco(),
						"pix" => $objModel->getChavepix(),
						"criadopor" => $objModel->getCriado_por(),
						"datacriacao" => $objModel->getData_criacao(),
						"horacriacao" => $objModel->getHora_criacao()
					];

					break;
				case FORMAPAGAMENTO_DINHEIRO :

					$binds = [ 
						"id_comdanda_fechamento" => $objModel->getComanda_fechamento_id(),
						"valor" => $objModel->getValor(),
						"id_forma_pagamento" => $objModel->getForma_pagamento_id(),
						"creddeb" => $objModel->getDbtcrd(),
						"maqui" => $objModel->getMaquineta(),
						"band" => $objModel->getBandeira(),
						"authcod" => $objModel->getCodauth(),
						"obs" => $objModel->getObservacao(),
						"din" => $objModel->getDinheiro(),
						"trc" => $objModel->getTroco(),
						"pix" => $objModel->getChavepix(),
						"criadopor" => $objModel->getCriado_por(),
						"datacriacao" => $objModel->getData_criacao(),
						"horacriacao" => $objModel->getHora_criacao()
					];

					break;
				case FORMAPAGAMENTO_PIX :

					$binds = [ 
						"id_comdanda_fechamento" => $objModel->getComanda_fechamento_id(),
						"valor" => $objModel->getValor(),
						"id_forma_pagamento" => $objModel->getForma_pagamento_id(),
						"creddeb" => $objModel->getDbtcrd(),
						"maqui" => $objModel->getMaquineta(),
						"band" => $objModel->getBandeira(),
						"authcod" => $objModel->getCodauth(),
						"obs" => $objModel->getObservacao(),
						"din" => $objModel->getDinheiro(),
						"trc" => $objModel->getTroco(),
						"pix" => $objModel->getChavepix(),
						"criadopor" => $objModel->getCriado_por(),
						"datacriacao" => $objModel->getData_criacao(),
						"horacriacao" => $objModel->getHora_criacao()
					];

					break;
				case FORMAPAGAMENTO_CREDITOCLIENTE :

					$binds = [ 
						"id_comdanda_fechamento" => $objModel->getComanda_fechamento_id(),
						"valor" => $objModel->getValor(),
						"id_forma_pagamento" => $objModel->getForma_pagamento_id(),
						"creddeb" => $objModel->getDbtcrd(),
						"maqui" => $objModel->getMaquineta(),
						"band" => $objModel->getBandeira(),
						"authcod" => $objModel->getCodauth(),
						"obs" => $objModel->getObservacao(),
						"din" => $objModel->getDinheiro(),
						"trc" => $objModel->getTroco(),
						"pix" => $objModel->getChavepix(),
						"criadopor" => $objModel->getCriado_por(),
						"datacriacao" => $objModel->getData_criacao(),
						"horacriacao" => $objModel->getHora_criacao()
					];

					break;
				default :

					break;
			}

			$conn = db_connect();
			$conn->query( $sql, $binds );
			$error = $conn->error();
			if ($error ['code'] == 0) {
				$pagamentoId = $conn->insertID();
				$objModel->setId( $pagamentoId );
				array_push( $lista_pagamentos, $objModel );
				if (intval( $objModel->getForma_pagamento_id() ) == FORMAPAGAMENTO_CREDITOCLIENTE) {
					$creditos = $objModel->getCreditoCliente();

					for($i = 0; $i < count( $creditos ); $i++) {
						$objCredito = CreditoCliente::builder()->setCreditoId( $creditos [$i]->credito_id )
							->setValorTotal( $creditos [$i]->valor_total )
							->setValorUsado( $creditos [$i]->valor_usado )
							->setGerarCredito( $creditos [$i]->gerar_credito )
							->build();

						$sql_credito = <<<SQL
							select  
								id,	extorno_id, credito_id,									
								valor, saldo, cliente_id, usado,
								criado_por,	data_criacao, hora_criacao, 
								atualizado_por, data_atualizacao, hora_atualizacao
							from
								credito_cliente
							where 
								id = :id: 
						SQL;

						$binds_credito = [ 
							'id' => $objCredito->getCreditoId()
						];

						$result_query = $conn->query( $sql_credito, $binds_credito )
							->getResultArray();

						$error_credito = $conn->error();
						if ($error_credito ['code'] == 0) {
							$usr_log = UsuarioLogado::getUsuarioId();
							$dt_atz = DateUtils::today();
							$hr_atz = DateUtils::now_time();
							if (is_array( $result_query )) {
								$orig_credito = CreditoCliente::builder()->setId( intval( $result_query [0] ['id'] ) )
									->setExtornoId( intval( $result_query [0] ['extorno_id'] ) )
									->setCreditoId( intval( $result_query [0] ['credito_id'] ) ?? 0)
									->setClienteId( intval( $result_query [0] ['cliente_id'] ) )
									->setCriadoPor( intval( $result_query [0] ['criado_por'] ) )
									->setDataCriacao( $result_query [0] ['data_criacao'] )
									->setHoraCriacao( $result_query [0] ['hora_criacao'] )
									->setValorTotal( 0.00 )
									->setValorUsado( 0.00 )
									->setValor( $result_query [0] ['valor'] )
									->setSaldo( $result_query [0] ['saldo'] )
									->setUsado( $result_query [0] ['usado'] )
									->setGerarCredito( '' )
									->setAtualizadoPor( intval( $result_query [0] ['atualizado_por'] ?? 0) )
									->setDataAtualizacao( $result_query [0] ['data_atualizacao'] )
									->setHoraAtualizacao( $result_query [0] ['hora_atualizacao'] )
									->build();
								if ($objCredito->getGerarCredito() == 'N') {
									$orig_credito->setAtualizadoPor( $usr_log );
									$orig_credito->setDataAtualizacao( $dt_atz );
									$orig_credito->setHoraAtualizacao( $hr_atz );
									$orig_credito->setUsado( 'S' );
									$orig_credito->setSaldo( 0.00 );

									$sql_update_credito = <<<SQL
											update credito_cliente
											set usado = :usado: , atualizado_por = :atz_por: ,
												data_atualizacao = :dt_atz: , hora_atualizacao = :hr_atz:,
												saldo = :saldo:
											where id = :id:
									SQL;

									$binds_update_credito = [ 
										'id' => $orig_credito->getId(),
										'usado' => $orig_credito->getUsado(),
										'atz_por' => $orig_credito->getAtualizadoPor(),
										'dt_atz' => $orig_credito->getDataAtualizacao(),
										'hr_atz' => $orig_credito->getHoraAtualizacao(),
										'saldo' => $orig_credito->getSaldo()
									];

									$resp = $conn->query( $sql_update_credito, $binds_update_credito );
									$affectedRows = $conn->affectedRows();
									$error_used_credito = $conn->error();
									if ($error_used_credito ['code'] != 0) {
										array_push( $lista_erros, $error_used_credito );
									}
								} else {
									$new_credito = CreditoCliente::builder()->setClienteId( $orig_credito->getClienteId() )
										->setCreditoId( $orig_credito->getId() )
										->setExtornoId( $orig_credito->getExtornoId() )
										->setClienteId( $orig_credito->getClienteId() )
										->setCriadoPor( $usr_log )
										->setDataCriacao( $dt_atz )
										->setHoraCriacao( $hr_atz )
										->setValorTotal( 0.00 )
										->setValorUsado( 0.00 )
										->setValor( 
										number_format( (floatval( $objCredito->getValorTotal() ) - floatval( $objCredito->getValorUsado() )), 2, '.', '' ) )
										->setSaldo( 
										number_format( (floatval( $objCredito->getValorTotal() ) - floatval( $objCredito->getValorUsado() )), 2, '.', '' ) )
										->setUsado( 'N' )
										->setGerarCredito( '' )
										->build();
									$orig_credito->setAtualizadoPor( $usr_log );
									$orig_credito->setDataAtualizacao( $dt_atz );
									$orig_credito->setHoraAtualizacao( $hr_atz );
									$orig_credito->setUsado( 'S' );
									$orig_credito->setSaldo( ($objCredito->getValorTotal() - $objCredito->getValorUsado()) );

									$sql_new_credito = <<<SQL
										insert into credito_cliente
										(extorno_id, credito_id, criado_por, data_criacao, hora_criacao, valor, saldo, cliente_id, usado) values
										(:id_extorno: , :id_credito:, :usr_cr:, :dt_cr:, :hr_cr:, :valor: , :saldo:, :id_cliente:, :usado:)
									SQL;

									$binds_new_credito = [ 
										'id_extorno' => $new_credito->getExtornoId(),
										'id_credito' => $new_credito->getCreditoId(),
										'usr_cr' => $usr_log,
										'dt_cr' => $dt_atz,
										'hr_cr' => $hr_atz,
										'valor' => $new_credito->getValor(),
										'saldo' => $new_credito->getSaldo(),
										'id_cliente' => $new_credito->getClienteId(),
										'usado' => $new_credito->getUsado()
									];
									$resp = $conn->query( $sql_new_credito, $binds_new_credito );

									$error_new_credito = $conn->error();
									if ($error_new_credito ['code'] == 0) {
										$newcreidtoid = $conn->insertID();
										if ($newcreidtoid > 0) {
											$sql_update_credito = <<<SQL
													update credito_cliente
													set usado = :usado: , atualizado_por = :atz_por: ,
														data_atualizacao = :dt_atz: , hora_atualizacao = :hr_atz:,
														saldo = :saldo:
													where id = :id:
											SQL;

											$binds_update_credito = [ 
												'id' => $orig_credito->getId(),
												'usado' => $orig_credito->getUsado(),
												'atz_por' => $orig_credito->getAtualizadoPor(),
												'dt_atz' => $orig_credito->getDataAtualizacao(),
												'hr_atz' => $orig_credito->getHoraAtualizacao(),
													'saldo' => number_format(floatval($orig_credito->getSaldo()), 2, '.', '' )
											];

											$resp = $conn->query( $sql_update_credito, $binds_update_credito );
											$affectedRows = $conn->affectedRows();
											$error_used_credito = $conn->error();
											if ($error_new_credito ['code'] != 0) {
												array_push( $lista_erros, $error_used_credito );
											}
										}
									} else {
										array_push( $lista_erros, $error_new_credito );
									}
								}
							}
						} else {
							array_push( $lista_erros, $error_credito );
						}
					}
				}
			} else {
				$err = $error;
				$err ["item"] = $objModel;
				array_push( $lista_erros, $err );
			}
			// $conn->close();
		}
		$resp = [ 
			"ok" => count( $lista_pagamentos ),
			"nok" => count( $lista_erros ),
			"pagamentos" => $lista_pagamentos,
			"error" => $error,
			"pagamentos_erros" => $lista_erros
		];
		return $resp;

	}

	private function updateComandaItemToPago(array $pagamento_lancamento_vm): array {

		$lista = array ();
		$usr = UsuarioLogado::getUsuarioId();

		foreach ( $pagamento_lancamento_vm as $obj ) {
			array_push( $lista, $obj );
		}
		$lista_pagamentos = array ();
		$lista_erros = array ();
		foreach ( $lista as $obj ) {
			$id = $obj->getComandaItemId();
			$data = DateUtils::today();
			$hora = DateUtils::now_time();
			$sql = <<<SQL
				update comanda_item
					set comanda_item_status_id = 2, 
						atualizado_por = :usr:, 
						data_atualizacao = :data:, 
						hora_atualizacao = :hora:
					where id = :item_id:
					 
			SQL;
			$binds = [ 
				"item_id" => $id,
				"usr" => $usr,
				"data" => "$data",
				"hora" => "$hora"
			];

			$conn = db_connect();
			$conn->query( $sql, $binds );
			$affectedRows = $conn->affectedRows();
			$error = $conn->error();
			if ($error->code == 0) {
				array_push( $lista_pagamentos, $obj );
			} else {
				$err = $error;
				$err ["item"] = $obj;
				array_push( $lista_erros, $err );
			}
			// $conn->close();
		}
		$resp = [ 
			"ok" => count( $lista_pagamentos ),
			"nok" => count( $lista_erros ),
			"pagamentos" => $lista_pagamentos,
			"error" => $error,
			"pagamentos_erros" => $lista_erros
		];

		return $resp;

	}

	private function persistProcedimentoExame(ProcedimentoRegistrationViewModel $procedimento_registration_vm, Procedimento $procedimento): ProcedimentoExame {

		$procedimento_model = new ProcedimentoExameModel();
		$array_prod = $procedimento_registration_vm->toArray();
		foreach ( $array_prod ['exame'] as $id ) {
			$procedimento_exame = ProcedimentoMapper::getProcedimentoExameFromProcedimentoRegistrationVM( $id, $procedimento->getId() );
			$procedimento_model->registerProcedimentoExame( $procedimento_exame );
		}
		return $procedimento_exame;

	}

	# -------------------------------------------------------------------------------------------------------------------#
	// public function getProcedimentoList(?Pagination $pagination, ?QueryFilterCollection $query_filter_collection,
	// ?QueryOrderCollection $query_order_collection = null): DAOResponse {

	// $sql = '
	// SELECT
	// procedimento.id AS id,
	// procedimento.descricao AS descricao,
	// tipo_procedimento.id AS id_tipo_procedimento,
	// tipo_procedimento.descricao as tipo_procedimento
	// FROM
	// procedimento,
	// tipo_procedimento
	// WHERE
	// procedimento.id_tipo_procedimento = tipo_procedimento.id
	// ';
	// return $this->getDAOResponseFromPaginatedSelect( [ ], $pagination, $query_filter_collection, $query_order_collection, $sql,
	// function (array $result_array) {
	// return ProcedimentoMapper::getProcedimentoDetailsVMCollectionFromArray( $result_array );
	// } );

	// }

	// public function getProcedimentoConsultaList(?Pagination $pagination, ?QueryFilterCollection $query_filter_collection,
	// ?QueryOrderCollection $query_order_collection = null): DAOResponse {

	// $sql = '
	// SELECT
	// procedimento.id AS id,
	// procedimento.descricao AS descricao,
	// tipo_procedimento.id AS id_tipo_procedimento,
	// tipo_procedimento.descricao as tipo_procedimento
	// FROM
	// procedimento,
	// tipo_procedimento
	// WHERE
	// tipo_procedimento.id = 2
	// and procedimento.id_tipo_procedimento = tipo_procedimento.id
	// ';
	// return $this->getDAOResponseFromPaginatedSelect( [ ], $pagination, $query_filter_collection, $query_order_collection, $sql,
	// function (array $result_array) {
	// return ProcedimentoMapper::getProcedimentoDetailsVMCollectionFromArray( $result_array );
	// } );

	// }

	// public function getProcedimentoInternacaoList(?Pagination $pagination, ?QueryFilterCollection $query_filter_collection,
	// ?QueryOrderCollection $query_order_collection = null): DAOResponse {

	// $sql = <<<SQL
	// SELECT
	// procedimento.id AS id,
	// procedimento.descricao AS descricao,
	// tipo_procedimento.id AS id_tipo_procedimento,
	// tipo_procedimento.descricao as tipo_procedimento
	// FROM
	// procedimento,
	// tipo_procedimento
	// WHERE
	// tipo_procedimento.id = 6
	// and procedimento.id_tipo_procedimento = tipo_procedimento.id
	// SQL;
	// return $this->getDAOResponseFromPaginatedSelect( [ ], $pagination, $query_filter_collection, $query_order_collection, $sql,
	// function (array $result_array) {
	// return ProcedimentoMapper::getProcedimentoDetailsVMCollectionFromArray( $result_array );
	// } );

	// }

	// public function getProcedimentoMedicacaoList(?Pagination $pagination, ?QueryFilterCollection $query_filter_collection,
	// ?QueryOrderCollection $query_order_collection = null): DAOResponse {

	// $sql = <<<SQL
	// SELECT
	// procedimento.id AS id,
	// procedimento.descricao AS descricao,
	// tipo_procedimento.id AS id_tipo_procedimento,
	// tipo_procedimento.descricao as tipo_procedimento
	// FROM
	// procedimento,
	// tipo_procedimento
	// WHERE
	// tipo_procedimento.id = 5
	// and procedimento.id_tipo_procedimento = tipo_procedimento.id
	// SQL;
	// return $this->getDAOResponseFromPaginatedSelect( [ ], $pagination, $query_filter_collection, $query_order_collection, $sql,
	// function (array $result_array) {
	// return ProcedimentoMapper::getProcedimentoDetailsVMCollectionFromArray( $result_array );
	// } );

	// }

	// public function getProcedimentoCirurgiaList(?Pagination $pagination, ?QueryFilterCollection $query_filter_collection,
	// ?QueryOrderCollection $query_order_collection = null): DAOResponse {

	// $sql = <<<SQL
	// SELECT
	// procedimento.id AS id,
	// procedimento.descricao AS descricao,
	// tipo_procedimento.id AS id_tipo_procedimento,
	// tipo_procedimento.descricao as tipo_procedimento
	// FROM
	// procedimento,
	// tipo_procedimento
	// WHERE
	// tipo_procedimento.id = 3
	// and procedimento.id_tipo_procedimento = tipo_procedimento.id
	// SQL;
	// return $this->getDAOResponseFromPaginatedSelect( [ ], $pagination, $query_filter_collection, $query_order_collection, $sql,
	// function (array $result_array) {
	// return ProcedimentoMapper::getProcedimentoDetailsVMCollectionFromArray( $result_array );
	// } );

	// }

	// public function deleteProcedimento(int $id_procedimento): DAOResponse {

	// $procedimento_model = new ProcedimentoModel();
	// $dao_response = $this->getDAOResponseForDeletion( $procedimento_model, $id_procedimento );
	// return $dao_response;

	// }

	// public function getṔrocedimento(QueryFilterCollection $query_filter_collection): DAOResponse {

	// $sql = '
	// SELECT
	// procedimento.id AS id,
	// procedimento.descricao AS descricao,
	// tipo_procedimento.id AS id_tipo_procedimento,
	// tipo_procedimento.descricao as tipo_procedimento
	// FROM
	// procedimento
	// LEFT JOIN tipo_procedimento ON tipo_procedimento.id = procedimento.id_tipo_procedimento
	// WHERE
	// procedimento.id_tipo_procedimento = tipo_procedimento.id
	// ';
	// $binds = [ ];
	// return $this->getDAOResponseFromUniqueRowSelect( $binds, $query_filter_collection, $sql,
	// function (array $result_array) {
	// $sql2 = 'SELECT exame.id AS id, exame.nome AS nome FROM procedimento_exame, exame
	// WHERE exame.id = procedimento_exame.id_exame AND procedimento_exame.id_procedimento =' . $result_array [0] ['id'];
	// $query = $this->db->query( $sql2 );
	// return ProcedimentoMapper::getProcedimentoDetailsVMFromArray( $result_array [0], $query->getResultArray() );
	// } );

	// }

	// public function getExames(int $id_procedimento) {

	// $sql = 'SELECT exame.id AS id, exame.nome AS nome FROM procedimento_exame, exame
	// WHERE exame.id = procedimento_exame.id_exame AND procedimento_exame.id_procedimento =' . $id_procedimento;
	// $binds = [ ];
	// $query = $this->db->query( $sql );
	// return $query->getResultArray();

	// }

	// public function getExamesFromProcedimentos(array $procedimentos) {

	// $values = '(' . implode( ',', $procedimentos ) . ')';
	// $sql = <<<SQL
	// SELECT
	// exame.id AS id,
	// exame.nome AS nome,
	// procedimento_exame.id_procedimento as procedimento_id
	// FROM procedimento_exame, exame
	// WHERE 1=1
	// AND exame.id = procedimento_exame.id_exame
	// AND procedimento_exame.id_procedimento in $values
	// SQL;
	// $query = $this->db->query( $sql );
	// return $query->getResultArray();

	// }

	# --------------------------------------------------------------------------------------------------------------#
	// public function persistProcedimentoUpdateVM(int $id_procedimento, ProcedimentoUpdateViewModel $procedimento_update_vm): DAOResponse {

	// $this->db->transStart();
	// $status_persistence = $this->persistProcedimentoFromProcedimentoUpdateVM( $id_procedimento, $procedimento_update_vm );
	// $pog = $procedimento_update_vm->toArray();
	// if (!empty( $pog ['exames'] )) {
	// $status_persistence_exame = $this->persistProcedimentoExameFromProcedimentoUpdateVM( $id_procedimento, $procedimento_update_vm );
	// }
	// $error = $this->db->error();
	// // $this->db->close();
	// $dao_response = new DAOResponse();
	// if ($error && $error ['code']) {
	// $status_response = $error ['code'];
	// $dao_response_errors = [ ];
	// if ($status_response === DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS) {
	// if (strpos( $error ['message'], 'fk_procedimento_id_tipo_procedimento' ) !== false) {
	// $dao_response_errors ['id_tipo_procedimento'] = 'Esse tipo de procedimento não existe.';
	// }
	// if (strpos( $error ['message'], 'fk_procedimento_alterado_por' ) !== false) {
	// $dao_response_errors ['alterado_por'] = 'Esse usuário não existe.';
	// }
	// }
	// if ($status_response === DAOResponseInterface::DUPLICATED_UNIQUE_KEY && strpos( $error ['message'], 'procedimento.descricao' ) !== false) {
	// $dao_response_errors ['descricao'] = 'Essa descrição de procedimento já existe.';
	// }
	// $dao_response->setErrors( $dao_response_errors );
	// (new LogService())->log_error( $status_response, "Ocorreu um erro durante a atualização do procedimento $id_procedimento",
	// $procedimento_update_vm->toArray() );
	// } else {
	// $this->db->transComplete();
	// $status_response = $status_persistence ? DAOResponseInterface::SUCESS : DAOResponseInterface::RECORD_NOT_FOUND;
	// }
	// $dao_response->setStatus( $status_response );
	// return $dao_response;

	// }

	// private function persistProcedimentoFromProcedimentoUpdateVM(int $id_procedimento, ProcedimentoUpdateViewModel $procedimento_update_vm): bool {

	// $procedimento_model = new ProcedimentoModel();
	// $procedimento = ProcedimentoMapper::getProcedimentoFromProcedimentoUpdateVM( $procedimento_update_vm );
	// $sucess_update = $procedimento_model->updateProcedimentoByID( $id_procedimento, $procedimento );
	// return $sucess_update;

	// }

	// private function persistProcedimentoExameFromProcedimentoUpdateVM(int $id_procedimento, ProcedimentoUpdateViewModel $procedimento_update_vm): bool {

	// $procedimento_model = new ProcedimentoExameModel();
	// $service_response = new ServiceResponse();
	// $dao_response = $this->deleteProcedimentoExame( $id_procedimento );
	// switch ($dao_response->getStatus()) {
	// case DAOResponseInterface::SUCESS :
	// break;
	// case DAOResponseInterface::ERROR_DELETING :
	// $service_response->setStatus( ServiceResponseInterface::ERROR_DELETING );
	// return false;
	// default :
	// $service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
	// return false;
	// }
	// foreach ( $procedimento_update_vm->getExames() as $id ) {
	// $procedimento_exame = ProcedimentoMapper::getProcedimentoExameFromProcedimentoRegistrationVM( $id, $id_procedimento );
	// $procedimento_model->registerProcedimentoExame( $procedimento_exame );
	// }
	// return true;

	// }

	// private function deleteProcedimentoExame(int $id_procedimento): DAOResponse {

	// $sql = "
	// DELETE procedimento_exame FROM procedimento_exame
	// WHERE procedimento_exame.id_procedimento = :id_procedimento:";

	// $binds = [
	// 'id_procedimento' => $id_procedimento
	// ];
	// $query = $this->db->query( $sql, $binds );
	// $affected_rows = $query->connID->affected_rows;
	// $dao_response = new DAOResponse();
	// if ($affected_rows < 0) {
	// $dao_response->setStatus( DAOResponseInterface::ERROR_DELETING );
	// return $dao_response;
	// } else {
	// $dao_response->setStatus( DAOResponseInterface::SUCESS );
	// return $dao_response;
	// }

	// }
}