<?php

namespace App\DAO;

use App\DAO\DAOResponse\DAOResponse;
use App\DAO\DAOResponse\DAOResponseInterface;
use App\DAO\Pagination\Pagination;
use App\Mappers\InternacaoMapper;
use App\Services\AnamneseService;
use App\Services\ConsultaService;
use App\Services\FormularioService;
use App\Services\JWT\UsuarioLogado;
use App\Services\LogService;
use App\Utils\Collections\QueryFilterCollection;
use App\Utils\Collections\QueryOrderCollection;
use App\Utils\DateUtils;
use Exception;

class InternacaoDAO extends DAO {

	public function persistSaidaInternacaoAltaObitoRegistration($procedimento, $id_cliente, $id_pet, $id_unidade, $data_post): DAOResponse {

		$dao_response = new DAOResponse();
		try {
			$this->db->transStart();

			// CRIAÇÃO DA REQUISIÇÃO DE PROCEDIMENTO
			$convenio_procedimento = $this->getConvenioProcedimento( $procedimento, $id_unidade );
			$requisicao_procedimento = $this->persistRequisicaoProcedimento( $convenio_procedimento, $id_pet );
			$internacao_pet = $this->persistInternacaoPetAlta( $procedimento, $id_pet, $id_unidade, $requisicao_procedimento );

			// CRIAÇÃO DA COMANDA
			$comanda = $this->persistComanda( $requisicao_procedimento, $id_cliente, $id_pet, $id_unidade );
			$comanda_item = $this->persistComandaItem( $requisicao_procedimento, $comanda, $convenio_procedimento );

			// CRIAÇÃO DO AGENDAMENTO E CONSULTA (MARCA COMO EXECUTADO)
			// $data['id_requisicao_procedimento'] = $requisicao_procedimento;
			// $agendamentoDao = new ConsultaDAO();
			// $id_agendamento = $agendamentoDao->registerAgendamentoBaseRequisicao( $data );
			// $id_consulta = $agendamentoDao->registerConsultaEndpointRequisicao( $id_agendamento );
			// $agendamentoDao->updateRequisicaoProcedimento( $requisicao_procedimento, $id_consulta );

			// var_dump($id_agendamento);
			// var_dump($comanda_item);

			// PERSISTENCIA DO FORMULÁRIO
			$service_response = $this->persistConsultaFormulario( $data_post, $requisicao_procedimento );

			if ($service_response->status != 1) {
				$status_persistence = $service_response->status;
				$dao_response_errors = [ ];
				// if (strpos($error['message'],'PROCEDIMENTO.descricao') !== false) {
				// $dao_response_errors['descricao'] = 'Esse procedimento já existe';
				// }
				$dao_response->setErrors( $dao_response_errors );
				log_message( 'error', "Falha ao cadastrar consulta" );
				$this->db->transRollback();
			} else {
				$this->db->transComplete();
				$status_persistence = DAOResponseInterface::SUCESS;
			}
		} catch ( Exception $exception ) {
			log_message( 'error', json_encode( $this->db->error() ) );
			$this->db->transRollback();
			$status_persistence = DAOResponseInterface::DATABASE_CONNECTION_ERROR;
			$internacao = null;
		}
		$this->db->close();
		$dao_response->setStatus( $status_persistence );
		if ($status_persistence === DAOResponseInterface::SUCESS) {
			$dao_response->setData( $internacao );
		}
		return $dao_response;

	}

	private function getConvenioProcedimento($procedimento, $id_unidade) {

		$id = 0;
		if ($procedimento == 1) :
			$id = 969;
		 elseif ($procedimento == 2) :
			$id = 970;
		 elseif ($procedimento == 3) :
			$id = 971;
		endif;

		$sqlBuscaConvenioProcedimento = <<<SQL
		    select id from convenio_procedimento cp where cp.id_procedimento = $id and id_unidade = $id_unidade
		SQL;

		$query_result = $this->db->query( $sqlBuscaConvenioProcedimento )
			->getResult();
		$convenio_procedimento_id = $query_result [0]->id;
		return $convenio_procedimento_id;

	}

	private function persistRequisicaoProcedimento($convenio_procedimento_id, $id_pet) {

		$usr = UsuarioLogado::getUsuarioId();
		// Cria a requisição do procedimento
		$sql = <<<SQL
		    insert into requisicao_procedimento 
			(id_medico, id_convenio_procedimento, id_consulta, status_id, usuario_executor, 
			id_requisitante, data_requisicao, hora_requisicao, data_execucao, hora_execucao, id_pet)
		    values (
		        :id_medico:,
		        :id_convenio_procedimento:,
		        :id_consulta:,
		        :status_id:,
		        :usuario_executor:,
				:id_requisitante:,
		        :data_requisicao:,
		        :hora_requisicao:,
		        :data_execucao:,
		        :hora_execucao:,
		        :id_pet:
		    )
		SQL;

		$binds = [ 
			'id_medico' => null,
			'id_convenio_procedimento' => $convenio_procedimento_id,
			'id_consulta' => null,
			'status_id' => 1, // CRIADO
			'usuario_executor' => UsuarioLogado::getUsuarioId(),
			'id_requisitante' => $usr,
			'data_requisicao' => date( 'Y-m-d' ),
			'hora_requisicao' => date( 'H:i:s' ),
			'data_execucao' => '1900-01-01',
			'hora_execucao' => '00:00:00',
			'id_pet' => ( int ) $id_pet
		];

		$this->db->query( $sql, $binds )->numRows;
		$error = $this->db->error();
		$requisicaoId = $this->db->insertID();

		return $requisicaoId;

	}

	private function persistComanda($requisicaoId, $id_cliente, $id_pet, $id_unidade) {

		// Cria a comanda e gera item pra comanda
		$requisicaoProcedimentoId = $requisicaoId;

		$sqlInserirComanda = <<<SQL
		    insert into comanda (data_criada, hora_criada, criado_por, data_fechada, hora_fechada, id_cliente, id_pet, id_unidade, fechado_por)
		    values (
		        :data_criada:,
		        :hora_criada:,
		        :criado_por:,
		        :data_fechada:,
		        :hora_fechada:,
		        :id_cliente:,
		        :id_pet:,
		        :id_unidade:,
		        :fechado_por:
		    )
		SQL;
		$bindsInserirComanda = [ 
			'data_criada' => date( 'Y-m-d' ),
			'hora_criada' => date( 'H:i:s' ),
			'criado_por' => UsuarioLogado::getUsuarioId(),
			'data_fechada' => '1900-01-01',
			'hora_fechada' => '00:00:00',
			'id_cliente' => ( int ) $id_cliente,
			'id_pet' => ( int ) $id_pet,
			'id_unidade' => ( int ) $id_unidade,
			'fechado_por' => null
		];

		$sqlComandaAtiva = <<<SQL
		    select 
		        id as comanda_id
		    from comanda c
		    WHERE
		        id_cliente = :cliente_id:
		        and id_pet = :id_pet:
		        and id_unidade = :id_unidade:
		        and fechado_por is null
		SQL;
		$comandaAtiva = $this->db->query( $sqlComandaAtiva,
			[ 
				'cliente_id' => ( int ) $id_cliente,
				'id_pet' => ( int ) $id_pet,
				'id_unidade' => ( int ) $id_unidade
			] )
			->getResultArray();
		$comandaAtivaId = count( $comandaAtiva ) ? $comandaAtiva [0] ['comanda_id'] : 0;
		$usuarioId = UsuarioLogado::getUsuarioId();

		if ($comandaAtivaId) {
			$comandaId = $comandaAtivaId;
		} else {
			$this->db->query( $sqlInserirComanda, $bindsInserirComanda );
			$comandaId = $this->db->insertID();
		}
		return $comandaId;

	}

	private function persistComandaItem($requisicaoProcedimentoId, $comandaId, $convenio_procedimento_id) {

		$usuarioId = UsuarioLogado::getUsuarioId();
		$sqlInserirComandaItem = <<<SQL
		    insert into comanda_item 
		        (id_comanda, id_procedimento, id_convenio, valor, status_item, criado_por
		        , comanda_item_status_id, data_criacao, hora_criacao, id_requisicao_procedimento)
		    select
		        $comandaId as id_comanda
		        ,cp.id_procedimento as id_procedimento
		        ,cp.id_convenio as id_convenio
		        ,pv.valor as valor
		        ,0 as status_item 
		        ,$usuarioId as criado_por
		        ,2 as comanda_item_status_id
		        ,now() as data_criacao
		        ,now() as hora_criacao
		        ,$requisicaoProcedimentoId as id_requisicao_procedimento
		    from procedimento_valor pv
		    inner join convenio_procedimento cp on pv.id_convenio_procedimento = cp.id
		    where
		        pv.id_convenio_procedimento = :convenio_procedimento_id:
		        and ((NOW() BETWEEN pv.data_inicio and pv.data_fim) or (pv.data_inicio <= now() and pv.data_fim ='1900-01-01') ) 	
		    limit 1
		SQL;
		$bindsInserirComandaItem = [ 
			'convenio_procedimento_id' => $convenio_procedimento_id
		];
		$this->db->query( $sqlInserirComandaItem, $bindsInserirComandaItem );
		$comandaItemId = $this->db->insertID();
		$error = $this->db->error();
		if (!$error ['code']) {
			$sql_tipo_convenio = <<<SQL
				select
					rp.id as requisicao_id, rp.id_pet, cp.id as convenio_procedimento_id, 
					cp.id_convenio as convenio_id, tc.id as tipo_convenio_id ,
					tc.descricao as tipo_convenio
				from 
					requisicao_procedimento rp, convenio_procedimento cp, 
					convenio c , tipo_convenio tc
				where
					rp.id  = :requisicao_id:
					and rp.id_convenio_procedimento = cp.id
					and cp.id_convenio = c.id
					and c.id_tipo_convenio =tc.id 
			SQL;

			$binds_tipo_convenio = [ 
				'requisicao_id' => $requisicaoProcedimentoId
			];

			$result_tc = $this->db->query( $sql_tipo_convenio, $binds_tipo_convenio )
				->getResultArray();
			$error = $this->db->error();

			if (!$error ['code']) {
				$idTipoConvenio = $result_tc [0] ['tipo_convenio_id'];
				if ((intval( $idTipoConvenio ) == 1) || (intval( $idTipoConvenio ) == 3)) {
					$sql_update_pbpg = <<<SQL
						update comanda_item
						set comanda_item_status_id = 2
						where id_requisicao_procedimento = :requisicao_id:
					SQL;
					$binds_update_pbpg = [ 
						'requisicao_id' => $requisicaoProcedimentoId
					];
					$this->db->query( $sql_update_pbpg, $binds_update_pbpg );
					$error = $this->db->error();
				}
			}
		}
		return $comandaItemId;

	}

	public function persistInternacaoPetAlta($procedimento, $id_pet, $id_unidade, $id_requisicao) {

		$status = 0;
		if ($procedimento == 1) :
			$status = 2;
		 elseif ($procedimento == 2) :
			$status = 2;
		 elseif ($procedimento == 3) :
			$status = 3;
		endif;

		// Cria a internação do pet
		$sql = <<<SQL
		    INSERT INTO internacao_pet
		        (id_pet, id_unidade, id_requisicao, status, criado_em, alterado_em, criado_por, alterado_por)
		    VALUES  (:id_pet:, :id_unidade:, :id_requisicao:, :status:, :criado_em:, :alterado_em:, :criado_por:, :alterado_por:);
		SQL;

		$binds = [ 
			'id_pet' => ( int ) $id_pet,
			'id_unidade' => ( int ) $id_unidade,
			'id_requisicao' => ( int ) $id_requisicao,
			'status' => ( int ) $status, // ALTA MEDICA/OBITO
			'criado_em' => DateUtils::now(),
			'alterado_em' => DateUtils::now(),
			'criado_por' => UsuarioLogado::getUsuarioId(),
			'alterado_por' => UsuarioLogado::getUsuarioId()
		];

		$this->db->query( $sql, $binds )->numRows;
		$error = $this->db->error();
		$internacaoId = $this->db->insertID();

		return $internacaoId;

	}

	public function persistConsultaFormulario(array $data_post, $requisicao_procedimento) {

		$respostas = $data_post ['respostas'];
		$data_post ['id_requisicao_procedimento'] = $requisicao_procedimento;
		$formularioService = new FormularioService();
		$formulario = $formularioService->getFormularioByID( $data_post ['id_formulario'] );
		$perguntas = $formulario->getData() ['perguntas'];
		$resp = $formularioService->getReformatRespostasFormulario( $perguntas, $respostas );
		$data_post ['respostas'] = $resp;
		// $service = new AnamneseService();
		// $service_response = $service->saveAnamneseAdicional($data_post);

		$service = new ConsultaService();
		$service_response = $service->registerConsultaRequisicao( $data_post );

		return $service_response;

	}

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

		$sql = '
            SELECT 
                c.id as cliente_id, 
                pf.nome as nome_cliente, 
                p2.id as id_pet, 
                p2.nome as nome_pet, 
                rp.data_requisicao, 
                rp.hora_requisicao,
                rp.status_id as status_requisicao,
                rp.data_execucao,
                rp.usuario_executor,
                ip.status as internacao_status,
                (select ip3.criado_em from internacao_pet ip3 
	              where ip3.status = 1 and ip3.id_pet = ip.id_pet 
	              order by criado_em desc limit 1) as data_entrada_internacao,
	              ip.criado_em as data_saida_internacao
            FROM 
                internacao_pet ip
                inner join requisicao_procedimento rp ON ip.id_requisicao = rp.id 
                inner join pet p2 on rp.id_pet = p2.id
                inner join pet_cliente pc on p2.id = pc.id_pet 
                inner join cliente c on pc.id_cliente = c.id 
                inner join pessoa_fisica pf on pf.id_pessoa = c.id_pessoa 
            WHERE 
                ip.status in (1, 2)
				and ip.id_unidade = :unidade:
                and not exists (select 1 from internacao_pet ip2 where ip.id_pet = ip2.id_pet and ip2.status = 3 and ip2.criado_em > ip.criado_em)
                and ip.criado_em = (select max(ip2.criado_em) from internacao_pet ip2 where ip.id_pet = ip2.id_pet and ip2.status <> 3 )
                
        ';
		$binds = [ 
			'unidade' => $id_unidade
		];

		
		return $this->getDAOResponseFromPaginatedSelect( $binds, $pagination, $query_filter_collection, $query_order_collection, $sql, 
			function (array $result_array) {
				return InternacaoMapper::getInternacaoDetailsVMCollectionFromArray( $result_array );
			} );

	}

	public function registerInternacaoFromOrcamento($id_requisicao, $id_pet, $id_unidade) {

		$sqlBuscaProcedimento = <<<SQL
		        select p.id from requisicao_procedimento rp 
		        inner join convenio_procedimento cp on rp.id_convenio_procedimento = cp.id
		        inner join procedimento p on cp.id_procedimento = p.id
		        where rp.id = $id_requisicao limit 1
		SQL;

		$query_result = db_connect()->query( $sqlBuscaProcedimento )
			->getResult();
		$reponse_procedimento = $query_result [0]->id;

		// VALIDA SE O PROCEDIMENTO É ENTRADA DE INTERNAÇÃO
		if ($reponse_procedimento == 968) {
			$sql = <<<SQL
			    INSERT INTO internacao_pet 
			        (id_pet, id_unidade, id_requisicao, status, criado_em, alterado_em, criado_por, alterado_por)
			    VALUES (:id_pet:, :id_unidade:, :id_requisicao:, :status:, :criado_em:, :alterado_em:, :criado_por:, :alterado_por:);
			SQL;

			$binds = [ 
				'id_pet' => ( int ) $id_pet,
				'id_unidade' => ( int ) $id_unidade,
				'id_requisicao' => ( int ) $id_requisicao,
				'status' => 1, // ENTRADA INTERNAÇÃO
				'criado_em' => DateUtils::now(),
				'alterado_em' => DateUtils::now(),
				'criado_por' => UsuarioLogado::getUsuarioId(),
				'alterado_por' => UsuarioLogado::getUsuarioId()
			];

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

			return $internacaoId;
		}
		return 0;

	}

}