<?php

namespace App\Controllers;

use App\DAO\Filter\QueryFilter;
use App\Services\AgendamentoService;
use App\Services\JWT\JWTPayload\JWTPayload;
use App\Services\JWT\UsuarioLogado;
use App\Services\JWTService;
use App\Services\ServiceResponse\ServiceResponseInterface;
use App\Validations\AgendamentoClienteValidation;
use App\Validations\AgendamentoValidation;
use CodeIgniter\HTTP\Response;
use CodeIgniter\HTTP\ResponseInterface;
use DateTime;

class AgendamentoController extends BaseController {

	public function registerAgendamento() {

		if (!$this->validate( AgendamentoValidation::register() )) {
			return $this->response->setJSON( [ 
				'message' => 'Informe os dados corretamente.',
				'errors' => $this->validation->getErrors()
			] );
		}
		$agendamento_service_response = (new AgendamentoService())->registerAgendamento( $_POST );
		$response_messages = [ 
			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro de conexão com o banco de dados.'
			],
			ServiceResponseInterface::SUCESS => [ 
				'code' => ResponseInterface::HTTP_OK,
				'message' => 'O paciente foi agendado com sucesso.'
			],
			ServiceResponseInterface::VALIDATION_PARAMS_ERROR => [ 
				'code' => ResponseInterface::HTTP_BAD_REQUEST,
				'message' => 'Informe os dados corretamente.'
			]
		];
		return $this->getResponse( $agendamento_service_response, $response_messages );

	}

	public function registerReagendamento() {

		if (!$this->validate( AgendamentoValidation::register() )) {
			return $this->response->setJSON( [ 
				'message' => 'Informe os dados corretamente.',
				'errors' => $this->validation->getErrors()
			] );
		}
		$agendamento_service_response = (new AgendamentoService())->cancelAgendamento( $_POST ['id_desmarcado'] );
		$agendamento_service_response = (new AgendamentoService())->registerAgendamento( $_POST );
		$response_messages = [ 
			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro de conexão com o banco de dados.'
			],
			ServiceResponseInterface::SUCESS => [ 
				'code' => ResponseInterface::HTTP_OK,
				'message' => 'O paciente foi agendado com sucesso.'
			],
			ServiceResponseInterface::VALIDATION_PARAMS_ERROR => [ 
				'code' => ResponseInterface::HTTP_BAD_REQUEST,
				'message' => 'Informe os dados corretamente.'
			]
		];
		return $this->getResponse( $agendamento_service_response, $response_messages );

	}

	public function updateAgendamento(int $id_agendamento) {

		if (!$this->validate( AgendamentoValidation::update() )) {
			return $this->response->setJSON( [ 
				'message' => 'Informe os dados corretamente.',
				'errors' => $this->validation->getErrors()
			] );
		}
		$agendamento_service_response = (new AgendamentoService())->updateAgendamento( $id_agendamento, $_POST );
		$response_messages = [ 
			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro de conexão com o banco de dados.'
			],
			ServiceResponseInterface::SUCESS => [ 
				'code' => ResponseInterface::HTTP_OK,
				'message' => 'Os dados do agendamento foram atualizados com sucesso.'
			],
			ServiceResponseInterface::RECORD_NOT_FOUND => [ 
				'code' => ResponseInterface::HTTP_PARTIAL_CONTENT,
				'message' => 'Esse agendamento não existe.'
			],
			ServiceResponseInterface::INSUFFICIENT_DATA => [ 
				'code' => ResponseInterface::HTTP_BAD_REQUEST,
				'message' => 'Não foram fornecidos dados suficientes para fazer a atualização.'
			],
			ServiceResponseInterface::VALIDATION_PARAMS_ERROR => [ 
				'code' => ResponseInterface::HTTP_BAD_REQUEST,
				'message' => 'Informe os dados corretamente.'
			]
		];
		return $this->getResponse( $agendamento_service_response, $response_messages );

	}

	public function registerAgendamentoCliente() {

		if (!$this->validate( AgendamentoValidation::registerVisaoCliente() )) {
			return $this->response->setJSON( [ 
				'message' => 'Informe os dados corretamente.',
				'errors' => $this->validation->getErrors()
			] );
		}
		$agendamento_service_response = (new AgendamentoService())->registerAgendamentoVisaoCliente( $_POST );
		$response_messages = [ 
			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro de conexão com o banco de dados.'
			],
			ServiceResponseInterface::SUCESS => [ 
				'code' => ResponseInterface::HTTP_OK,
				'message' => 'Agendamento feito com sucesso!'
			],
			ServiceResponseInterface::UNAUTHORIZED => [ 
				'code' => ResponseInterface::HTTP_BAD_REQUEST,
				'message' => 'Informe os dados corretamente.'
			],
			ServiceResponseInterface::VALIDATION_PARAMS_ERROR => [ 
				'code' => ResponseInterface::HTTP_BAD_REQUEST,
				'message' => 'Informe os dados corretamente.'
			]
		];
		return $this->getResponse( $agendamento_service_response, $response_messages );

	}

	public function cancelAgendamento(int $id_agendamento) {

		$agendamento_service_response = (new AgendamentoService())->cancelAgendamento( $id_agendamento );
		$response_messages = [ 
			ServiceResponseInterface::SUCESS => [ 
				'code' => ResponseInterface::HTTP_OK,
				'message' => 'O cancelamento foi efetuado com sucesso.'
			],
			ServiceResponseInterface::UNAUTHORIZED => [ 
				'code' => ResponseInterface::HTTP_UNAUTHORIZED,
				'message' => 'Esse usuário não permissão para realizar essa operação.'
			],
			ServiceResponseInterface::RECORD_IS_LINKED => [ 
				'code' => ResponseInterface::HTTP_UNAUTHORIZED,
				'message' => 'Esse agendamento já está vinculado a uma consulta. Não pode ser, portanto, cancelado.'
			],
			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro interno do servidor.'
			],
			ServiceResponseInterface::RECORD_NOT_FOUND => [ 
				'code' => ResponseInterface::HTTP_PARTIAL_CONTENT,
				'message' => 'Essa agenda não foi encontrada.'
			]
		];
		return $this->getResponse( $agendamento_service_response, $response_messages );

	}


    public function cancelAgendamentoTelevet(int $id_agendamento) {

        $agendamento_service_response = (new AgendamentoService())->cancelAgendamentoTelevet( $id_agendamento );
        $response_messages = [
            ServiceResponseInterface::SUCESS => [
                'code' => ResponseInterface::HTTP_OK,
                'message' => 'O cancelamento foi efetuado com sucesso.'
            ],
            ServiceResponseInterface::UNAUTHORIZED => [
                'code' => ResponseInterface::HTTP_UNAUTHORIZED,
                'message' => 'Esse usuário não permissão para realizar essa operação.'
            ],
            ServiceResponseInterface::RECORD_IS_LINKED => [
                'code' => ResponseInterface::HTTP_UNAUTHORIZED,
                'message' => 'Esse agendamento já está vinculado a uma consulta. Não pode ser, portanto, cancelado.'
            ],
            ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [
                'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
                'message' => 'Erro interno do servidor.'
            ],
            ServiceResponseInterface::RECORD_NOT_FOUND => [
                'code' => ResponseInterface::HTTP_PARTIAL_CONTENT,
                'message' => 'Essa agenda não foi encontrada.'
            ]
        ];
        return $this->getResponse( $agendamento_service_response, $response_messages );

    }

	public function getAgendamentoByID(int $id_agendamento): Response {

		$query_filter = QueryFilter::builder()->setNameParam( 'id' )->setTable( 'agendamento' )->setValue( $id_agendamento )->setIsExact( true )->build();
		$assistente_service_response = (new AgendamentoService())->getAgendamento( $query_filter );
		$response_messages = [ 
			ServiceResponseInterface::SUCESS => [ 
				'code' => ResponseInterface::HTTP_OK,
				'message' => 'Os dados da agendamento foram encontrados com sucesso.'
			],
			ServiceResponseInterface::RECORD_NOT_FOUND => [ 
				'code' => ResponseInterface::HTTP_PARTIAL_CONTENT,
				'message' => 'Nenhum registro foi encontrado.'
			],
			ServiceResponseInterface::SERVICE_INTERNAL_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro interno do servidor.'
			],
			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [ 
				'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
				'message' => 'Erro interno do servidor.'
			]
		];
		return $this->getResponse( $assistente_service_response, $response_messages );

	}

	public function minhasConsultas() {

		$usuarioId = UsuarioLogado::getUsuarioId();
		if (UsuarioLogado::getProfileId() !== PERFIL_PACIENTE) {
			return $this->response->setStatusCode( 403 );
		}
		$sql = <<<SQL
		    SELECT 
		        ag.id as agendamento_id,
		        a.id as agenda_id,
		        ag.id_paciente as paciente_id,
		        ap.id_pet as pet_id,
		        p.nome as pet_nome,
		        p2.descricao as procedimento_descricao,
		        p2.id as procedimento_id,
		        coalesce(c.id, 0) as encerrado,
		        if (left(ag.cancelado_em, 10) = '0000-00-00', '1900-01-01 00:00:00',coalesce(ag.cancelado_em, '1900-01-01 00:00:00')) as cancelado_em,
		        tp.id as tipo_procedimento_id,
		        tp.descricao as tipo_procedimento_descricao,
		        a.`data` as `data`,
		        a.hora_inicio as hora_inicio,
		        a.hora_final as hora_final,
		        u.id as id_usuario_cliente
		    from agendamento ag
		    inner join cliente cli on ag.id_cliente = cli.id
		    inner join pessoa pes on pes.id = cli.id_pessoa 
		    inner join usuario u on u.id_pessoa = pes.id
		    inner join agenda a on a.id = ag.id_agenda 
		    inner join agendamento_pet ap on ap.id_agendamento = ag.id
		    inner join pet p on p.id = ap.id_pet 
		    inner join procedimento p2 on p2.id = ag.id_procedimento
		    inner join tipo_procedimento tp on tp.id = p2.id_tipo_procedimento 
		    left join consulta c on c.id_agendamento = ag.id
		    WHERE 1=1
		        and u.id = :usuario_id:
		    order by a.`data`, a.hora_inicio 
		SQL;
		$data = db_connect()->query( $sql, [ 
			'usuario_id' => $usuarioId
		] )->getResultArray();
		return $this->response->setStatusCode( count( $data ) > 0 ? 200 : 404 )->setJSON( [ 
			'message' => 'Dados encontrados com sucesso.',
			'data' => $data
		] );

	}

	public function agendarProximoSlotLivre() {

		$bodyRequest = [ 
			'petId' => ( int ) $_POST ['petId'],
			'unidadeId' => ( int ) $_POST ['unidadeId'],
			'medicoId' => ( int ) $_POST ['medicoId'],
			'tipoProcedimentoId' => ( int ) $_POST ['tipoProcedimentoId'],
			'procedimentoId' => ( int ) $_POST ['procedimentoId'],
			'requisicaoId' => ( int ) $_POST ['requisicaoId']
		];

		if (!$bodyRequest ['petId']) {
			die( 'Informe o pet.' );
		}
		if (!$bodyRequest ['unidadeId']) {
			die( 'Informe a unidad.' );
		}
		if (!$bodyRequest ['medicoId']) {
			die( 'Informe o médico.' );
		}
		if (!$bodyRequest ['tipoProcedimentoId']) {
			die( 'Informe o tipo de procedimento.' );
		}
		if (!$bodyRequest ['procedimentoId']) {
			die( 'Informe o procedimento.' );
		}
		if (!$bodyRequest ['requisicaoId']) {
			die( 'Informe a requisicao.' );
		}

		// $sqlDadosPaciente = <<<SQL
		// SELECT
		// p.id as pet_id,
		// c.id as cliente_id,
		// pac.id as paciente_id
		// from pet p, pet_cliente pc, cliente c, pessoa pes, paciente pac
		// inner join pet_cliente pc on pc.id_pet = p.id
		// inner join cliente c on c.id = pc.id_cliente
		// inner join pessoa pes on pes.id = c.id_pessoa
		// inner join paciente pac on pac.id_pessoa = pes.id
		// WHERE
		// p.id = :pet_id:
		// limit 1
		// SQL;
		$sqlDadosPaciente = <<<SQL
		    SELECT 
		        p.id as pet_id,
		        c.id as cliente_id,
		        pac.id as paciente_id
		    from pet p, pet_cliente pc, cliente c, pessoa pes, paciente pac
		    where 
		        p.id = :pet_id:
				and pc.id_pet = p.id
				and c.id = pc.id_cliente
				and pes.id = c.id_pessoa
				and pac.id_pessoa = pes.id
		    limit 1
		SQL;

		$binds = [ 
			'pet_id' => $bodyRequest ['petId']
		];

		$conn = db_connect();
		$query = $conn->query( $sqlDadosPaciente, $binds )->getResultArray();
		if (count( $query )) {
			$query = $query [0];
		} else {
			die( 'Esse pet não existe.' );
		}
		$bodyRequest ['pacienteId'] = ( int ) $query ['paciente_id'];
		$bodyRequest ['clienteId'] = ( int ) $query ['cliente_id'];

		$sqlProximaAgendaLivre = <<<SQL
		    select a.id as agenda_id from agenda a 
		    left join agendamento ag on ag.id_agenda = a.id
		    where 1=1 
		        and a.id_medico = :medico_id:
		        and ag.id is null
		        and left(now(),10) =  a.`data` 
		    limit 1
		SQL;

		$agendaLivreQuery = $conn->query( $sqlProximaAgendaLivre, [ 
			'medico_id' => $bodyRequest ['medicoId']
		] )->getResultArray();

		if (count( $agendaLivreQuery ) > 0) {
			$agendaId = ( int ) $agendaLivreQuery [0] ['agenda_id'];
		} else {
			$sqlInsertAgenda = <<<SQL
			    insert into agenda (codigo,id_medico,data,hora_inicio, hora_final, id_tipo_procedimento, adicionado_por, alterado_por, criado_em,alterado_em,id_unidade, id_assistente)
			    values (
			        :codigo:,
			        :id_medico:,
			        :data:,
			        :hora_inicio:,
			        :hora_final:,
			        :id_tipo_procedimento:,
			        :adicionado_por:,
			        :alterado_por:,
			        :criado_em:,
			        :alterado_em:,
			        :id_unidade:, 
			        :id_assistente:	
			    )
			SQL;
			$currdate = date( 'Y-m-d' );
			$bindsInsertAgenda = [ 
				'codigo' => $bodyRequest ['medicoId'] . '-' . $bodyRequest ['unidadeId'] . '-' . date( 'Ymd' ) . '00000000' . date( 'Ymdhis' ),
				'id_medico' => $bodyRequest ['medicoId'],
				'data' => $currdate,
				'hora_inicio' => date( 'H:i:s' ),
				'hora_final' => date( 'H:i:s' ),
				'id_tipo_procedimento' => $bodyRequest ['tipoProcedimentoId'],
				'adicionado_por' => UsuarioLogado::getUsuarioId(),
				'alterado_por' => null,
				'criado_em' => date( 'Y-m-d H:i:s' ),
				'alterado_em' => null,
				'id_unidade' => $bodyRequest ['unidadeId'],
				'id_assistente' => null
			];
			$conn->query( $sqlInsertAgenda, $bindsInsertAgenda );
			$agendaId = $conn->insertID();
		}

		$agendamentoCriacaoSql = <<<SQL
		     insert into agendamento 
					(id_agenda, id_cliente, id_paciente, id_procedimento, codigo, 
					cancelado_em, adicionado_por, alterado_por, alterado_em, criado_em, 
					atrasado, id_requisicao)
		     values (
		        :id_agenda:,
		        :id_cliente:,
		        :id_paciente:,
		        :id_procedimento:, 
		        :codigo:, 
		        :cancelado_em:,
		        :adicionado_por:, 
		        :alterado_por:, 
		        :alterado_em:, 
		        :criado_em:, 
		        :atrasado:,
				:id_requisicao:
		     )
		SQL;

		$binds = [ 
			'id_agenda' => $agendaId,
			'id_cliente' => $bodyRequest ['clienteId'],
			'id_paciente' => $bodyRequest ['pacienteId'],
			'id_procedimento' => $bodyRequest ['procedimentoId'],
			'codigo' => $agendaId . '_' . date( 'Ymd' ) . ' ' . '00:00:00',
			'cancelado_em' => null,
			'adicionado_por' => UsuarioLogado::getUsuarioId(),
			'alterado_por' => null,
			'alterado_em' => null,
			'criado_em' => date( 'Y-m-d H:i:s' ),
			'atrasado' => 0,
			'id_requisicao' => $bodyRequest ['requisicaoId']
		];

		$sqlAgendamentoPet = <<<SQL
		    insert into agendamento_pet (id_agendamento, id_pet)
		    values (:id_agendamento:, :id_pet:)
		SQL;
		$conn = db_connect();
		$conn->transBegin();
		$conn->query( $agendamentoCriacaoSql, $binds );
		$agendamentoId = $conn->insertID();
		$conn->query( $sqlAgendamentoPet, [ 
			'id_agendamento' => $agendamentoId,
			'id_pet' => $bodyRequest ['petId']
		] );
		if ($agendamentoId) {
			$conn->transCommit();
		}
		return $this->response->setStatusCode( 200 )->setJSON( [ 
			'message' => 'O paciente foi agendado com sucesso..',
			'data' => $agendamentoId
		] );

    
    }
    public function getAgendamentoSalaByID (int $id_requisicao_procedimento) :  Response {
    	$assistente_service_response = (new AgendamentoService())->getAgendamentoSala($id_requisicao_procedimento);
    	$response_messages = [
    			ServiceResponseInterface::SUCESS => [
    					'code' => ResponseInterface::HTTP_OK,
    					'message' => 'Os dados da sala foram encontrados com sucesso.'
    			],
    			ServiceResponseInterface::RECORD_NOT_FOUND => [
    					'code' => ResponseInterface::HTTP_PARTIAL_CONTENT,
    					'message' => 'Nenhum registro foi encontrado.'
    			],
    			ServiceResponseInterface::SERVICE_INTERNAL_ERROR => [
    					'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
    					'message' => 'Erro interno do servidor.'
    			],
    			ServiceResponseInterface::DATABASE_CONNECTION_ERROR => [
    					'code' => ResponseInterface::HTTP_INTERNAL_SERVER_ERROR,
    					'message' => 'Erro interno do servidor.'
    			],
    	];
    	return $this->getResponse($assistente_service_response, $response_messages);
    }

}
