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

require APPPATH . '/libraries/REST_Controller.php';

class BotMenuPrincipal extends REST_Controller
{
    public function __construct()
    {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Headers: Content-Type, Cache-Control');
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT');

        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            exit;
        }

        parent::__construct();

        if (file_exists(APPPATH . 'models/BotRepository_model.php')) {
            $this->load->model('BotRepository_model', 'botRepo');
        }
    }

    public function index_post()
    {
        $payload = $this->getRequestPayload();
        $text = isset($payload['text']) ? trim((string) $payload['text']) : '';
        $cycle = isset($payload['cycle']) ? (int) $payload['cycle'] : -1;

        if ($cycle < 100 || $cycle > 399) {
            $data = $this->errorResponse('Invalid cycle for menu principal.', [
                'cycle' => $cycle,
                'valid_ranges' => ['100-199', '200-299', '300-399'],
            ]);
            $this->sendResponse($data);
            return;
        }

        if ($cycle >= 100 && $cycle <= 199) {
            $data = $this->handleRegistroVotantes($cycle, $text);
            $this->sendResponse($data);
            return;
        }

        if ($cycle >= 200 && $cycle <= 299) {
            $data = $this->handleRegistroVotos($cycle, $text);
            $this->sendResponse($data);
            return;
        }

        $data = $this->handleConsultaEstado($cycle, $text);
        $this->sendResponse($data);
    }

    public function index_options()
    {
        $this->set_response(null, REST_Controller::HTTP_NO_CONTENT);
    }

    private function handleRegistroVotantes($cycle, $text)
    {
        switch ($cycle) {
            case 100:
                $option = $this->parseMainMenuOption($text);
                if ($option === 'movilizador') {
                    return $this->okResponse([
                        'next_cycle' => 1,
                        'handoff_endpoint' => '/api/bot-registro-movilizador',
                        'message' => 'Debes continuar en el endpoint de registro movilizador.',
                    ]);
                }
                if ($option === 'votantes') {
                    return $this->okResponse([
                        'next_cycle' => 101,
                        'message' => 'Registro de votantes. Responde: Iniciar o Volver al menu.',
                    ]);
                }
                if ($option === 'voto') {
                    return $this->okResponse([
                        'next_cycle' => 201,
                        'message' => 'Registro de votacion. Responde: Votos o Volver al menu.',
                    ]);
                }
                if ($option === 'estado') {
                    return $this->okResponse([
                        'next_cycle' => 301,
                        'message' => 'Consulta de estado. Responde: Consultar ahora o Volver al menu.',
                    ]);
                }

                return $this->keywordNotFound();

            case 101:
                $decision = $this->normalize($text);
                if ($this->isMenuBack($decision)) {
                    return $this->backToMenu();
                }
                if ($decision === 'iniciar') {
                    return $this->okResponse([
                        'next_cycle' => 102,
                        'message' => 'Escribe tu numero de cedula para validar que estas registrado como MOVILIZADOR.',
                    ]);
                }
                return $this->validationResponse('Respuesta no valida. Escribe Iniciar o Volver al menu.', 101);

            case 102:
                if (!$this->isCedula($text)) {
                    return $this->validationResponse('Cedula invalida. Debe tener solo numeros.', 102);
                }
                if (!$this->existsMovilizador($text)) {
                    return $this->validationResponse('Cedula no registrada como movilizador.', 102, ['retry_or_menu' => true]);
                }
                return $this->okResponse([
                    'next_cycle' => 103,
                    'message' => 'Escribe el nombre completo del votante.',
                    'captured' => ['movilizador_cedula' => $text],
                ]);

            case 103:
                if (!preg_match('/^[a-zA-Z\s]{5,120}$/', $text)) {
                    return $this->validationResponse('Nombre invalido. Usa solo letras y espacios.', 103);
                }
                return $this->okResponse([
                    'next_cycle' => 104,
                    'message' => 'Escribe el numero de cedula del votante (solo numeros).',
                    'captured' => ['votante_nombre' => $text],
                ]);

            case 104:
                if (!$this->isCedula($text)) {
                    return $this->validationResponse('Cedula invalida. Debe tener solo numeros.', 104);
                }
                if ($this->existsVotante($text)) {
                    return $this->validationResponse('Esta cedula ya fue registrada en el sistema. Intenta con otra cedula.', 104, ['retry_or_menu' => true]);
                }
                return $this->okResponse([
                    'next_cycle' => 105,
                    'message' => 'Escribe el centro de votacion. Ejemplo: Colegio San Martin - Bogota.',
                    'captured' => ['votante_cedula' => $text],
                ]);

            case 105:
                if (strlen($text) < 4 || strlen($text) > 140) {
                    return $this->validationResponse('Centro de votacion invalido.', 105);
                }
                return $this->okResponse([
                    'next_cycle' => 106,
                    'message' => 'Escribe el numero de contacto sin espacios ni signos.',
                    'captured' => ['centro_votacion' => $text],
                ]);

            case 106:
                if (!preg_match('/^[0-9]{7,15}$/', $text)) {
                    return $this->validationResponse('Numero de contacto invalido. Solo numeros (7 a 15 digitos).', 106);
                }
                return $this->okResponse([
                    'next_cycle' => 107,
                    'message' => 'Escribe el usuario de Instagram (sin @).',
                    'captured' => ['contacto' => $text],
                ]);

            case 107:
                if (!preg_match('/^[a-zA-Z0-9._]{3,30}$/', $text)) {
                    return $this->validationResponse('Usuario de Instagram invalido.', 107);
                }
                return $this->okResponse([
                    'next_cycle' => 108,
                    'message' => 'Confirma los datos. Responde: Confirmar, Corregir o Cancelar.',
                    'captured' => ['instagram' => $text],
                ]);

            case 108:
                $decision = $this->normalize($text);
                if ($decision === 'confirmar') {
                    return $this->okResponse([
                        'next_cycle' => 109,
                        'message' => 'Votante registrado. Deseas registrar otro votante? Responde: Iniciar o Volver al menu.',
                        'requires_action' => 'guardar_votante',
                    ]);
                }
                if ($decision === 'corregir') {
                    return $this->okResponse([
                        'next_cycle' => 103,
                        'message' => 'De acuerdo. Reiniciamos captura del votante. Escribe nombre completo.',
                    ]);
                }
                if ($decision === 'cancelar') {
                    return $this->okResponse([
                        'next_cycle' => 100,
                        'message' => 'No se guardo ningun dato. Regresando al menu principal.',
                    ]);
                }
                return $this->validationResponse('Respuesta no valida. Usa Confirmar, Corregir o Cancelar.', 108);

            case 109:
                $decision = $this->normalize($text);
                if ($decision === 'iniciar') {
                    return $this->okResponse([
                        'next_cycle' => 103,
                        'message' => 'Escribe el nombre completo del siguiente votante.',
                    ]);
                }
                if ($this->isMenuBack($decision)) {
                    return $this->backToMenu();
                }
                return $this->validationResponse('Respuesta no valida. Usa Iniciar o Volver al menu.', 109);

            default:
                return $this->validationResponse('Cycle no implementado en registro de votantes.', $cycle);
        }
    }

    private function handleRegistroVotos($cycle, $text)
    {
        switch ($cycle) {
            case 201:
                $decision = $this->normalize($text);
                if ($decision === 'votos' || $decision === 'iniciar') {
                    return $this->okResponse([
                        'next_cycle' => 202,
                        'message' => 'Escribe tu numero de cedula para validar MOVILIZADOR.',
                    ]);
                }
                if ($this->isMenuBack($decision)) {
                    return $this->backToMenu();
                }
                return $this->validationResponse('Respuesta no valida. Escribe Votos o Volver al menu.', 201);

            case 202:
                if (!$this->isCedula($text)) {
                    return $this->validationResponse('Cedula invalida. Debe tener solo numeros.', 202);
                }
                if (!$this->existsMovilizador($text)) {
                    return $this->validationResponse('Cedula no registrada como movilizador.', 202, ['retry_or_menu' => true]);
                }
                if (!$this->movilizadorTieneVotantes($text)) {
                    return $this->validationResponse('No tienes votantes registrados. Primero registra votantes.', 202, ['go_register_voters_or_menu' => true]);
                }
                return $this->okResponse([
                    'next_cycle' => 203,
                    'message' => 'Escribe la cedula del votante que ya voto.',
                    'captured' => ['movilizador_cedula' => $text],
                ]);

            case 203:
                if (!$this->isCedula($text)) {
                    return $this->validationResponse('Cedula invalida. Debe tener solo numeros.', 203);
                }
                if (!$this->existsVotante($text)) {
                    return $this->validationResponse('Esta cedula no se encuentra registrada en el sistema.', 203, ['retry_or_menu' => true]);
                }
                if (!$this->votantePerteneceAMovilizador($text)) {
                    return $this->validationResponse('Esta cedula no pertenece a tus votantes registrados.', 203, ['retry_or_menu' => true]);
                }
                return $this->okResponse([
                    'next_cycle' => 204,
                    'message' => 'Votante encontrado. Responde: Confirmar voto o Cancelar.',
                    'captured' => ['votante_cedula' => $text],
                ]);

            case 204:
                $decision = $this->normalize($text);
                if ($decision === 'cancelar') {
                    return $this->okResponse([
                        'next_cycle' => 203,
                        'message' => 'Operacion cancelada. Escribe otra cedula para registrar voto.',
                    ]);
                }
                if ($decision !== 'confirmar voto' && $decision !== 'confirmar') {
                    return $this->validationResponse('Respuesta no valida. Usa Confirmar voto o Cancelar.', 204);
                }

                if ($this->votanteYaVoto()) {
                    return $this->validationResponse('Este votante ya fue registrado como voto.', 203, ['retry_or_menu' => true, 'already_voted' => true]);
                }

                return $this->okResponse([
                    'next_cycle' => 205,
                    'message' => 'Voto registrado correctamente. Responde: Registrar otro voto o Volver al menu.',
                    'requires_action' => 'guardar_voto',
                ]);

            case 205:
                $decision = $this->normalize($text);
                if ($decision === 'registrar otro voto' || $decision === 'registrar voto' || $decision === 'otro') {
                    return $this->okResponse([
                        'next_cycle' => 203,
                        'message' => 'Escribe la cedula del siguiente votante que ya voto.',
                    ]);
                }
                if ($this->isMenuBack($decision)) {
                    return $this->backToMenu();
                }
                return $this->validationResponse('Respuesta no valida. Usa Registrar otro voto o Volver al menu.', 205);

            default:
                return $this->validationResponse('Cycle no implementado en registro de votacion.', $cycle);
        }
    }

    private function handleConsultaEstado($cycle, $text)
    {
        switch ($cycle) {
            case 301:
                $decision = $this->normalize($text);
                if ($decision === 'consultar ahora' || $decision === 'consultar') {
                    return $this->okResponse([
                        'next_cycle' => 302,
                        'message' => 'Escribe tu numero de cedula para validar MOVILIZADOR.',
                    ]);
                }
                if ($this->isMenuBack($decision)) {
                    return $this->backToMenu();
                }
                return $this->validationResponse('Respuesta no valida. Usa Consultar ahora o Volver al menu.', 301);

            case 302:
                if (!$this->isCedula($text)) {
                    return $this->validationResponse('Cedula invalida. Debe tener solo numeros.', 302);
                }
                if (!$this->existsMovilizador($text)) {
                    return $this->validationResponse('Cedula no registrada como movilizador.', 302, ['retry_or_menu' => true]);
                }
                return $this->okResponse([
                    'next_cycle' => 303,
                    'message' => 'Escribe la cedula del votante que deseas consultar.',
                    'captured' => ['movilizador_cedula' => $text],
                ]);

            case 303:
                if (!$this->isCedula($text)) {
                    return $this->validationResponse('Cedula invalida. Debe tener solo numeros.', 303);
                }
                if (!$this->existsVotante($text)) {
                    return $this->validationResponse('Esta cedula no se encuentra registrada en el sistema.', 303, ['retry_or_menu' => true]);
                }

                if ($this->estadoVotacionEsVotado()) {
                    return $this->okResponse([
                        'next_cycle' => 304,
                        'message' => 'Resultado: estado ya voto. Responde: Consultar otra cedula o Volver al menu.',
                        'result' => ['estado' => 'ya_voto'],
                    ]);
                }

                return $this->okResponse([
                    'next_cycle' => 304,
                    'message' => 'Resultado: aun no registra voto. Responde: Consultar otra cedula o Volver al menu.',
                    'result' => ['estado' => 'sin_voto'],
                ]);

            case 304:
                $decision = $this->normalize($text);
                if ($decision === 'consultar otra cedula' || $decision === 'consultar otra' || $decision === 'consultar') {
                    return $this->okResponse([
                        'next_cycle' => 303,
                        'message' => 'Escribe la siguiente cedula a consultar.',
                    ]);
                }
                if ($this->isMenuBack($decision)) {
                    return $this->backToMenu();
                }
                return $this->validationResponse('Respuesta no valida. Usa Consultar otra cedula o Volver al menu.', 304);

            default:
                return $this->validationResponse('Cycle no implementado en consulta de estado.', $cycle);
        }
    }

    private function parseMainMenuOption($text)
    {
        $n = $this->normalize($text);

        if (in_array($n, ['1', 'registrar movilizador', 'movilizador'], true)) {
            return 'movilizador';
        }
        if (in_array($n, ['2', 'registrar votantes', 'votantes', 'registrar votante'], true)) {
            return 'votantes';
        }
        if (in_array($n, ['3', 'registrar voto', 'registrar voto dia de eleccion', 'voto', 'votos'], true)) {
            return 'voto';
        }
        if (in_array($n, ['4', 'consultar estado', 'estado', 'consultar estado de votacion'], true)) {
            return 'estado';
        }

        return null;
    }

    private function isMenuBack($value)
    {
        return in_array($value, ['volver al menu', 'menu', 'volver'], true);
    }

    private function backToMenu()
    {
        return $this->okResponse([
            'next_cycle' => 100,
            'message' => 'Menu principal: 1) Registrar movilizador 2) Registrar votantes 3) Registrar voto 4) Consultar estado.',
        ]);
    }

    private function keywordNotFound()
    {
        return $this->validationResponse(
            'No reconocimos la opcion ingresada. Escribe una opcion valida del menu.',
            100,
            [
                'menu' => [
                    '1) Registrar movilizador',
                    '2) Registrar votantes',
                    '3) Registrar voto (dia de eleccion)',
                    '4) Consultar estado de votacion',
                ],
            ]
        );
    }

    private function getRequestPayload()
    {
        $text = $this->post('text', true);
        $cycle = $this->post('cycle', true);

        if ($text !== null || $cycle !== null) {
            return [
                'text' => $text,
                'cycle' => $cycle,
            ];
        }

        $raw = json_decode($this->input->raw_input_stream, true);
        return is_array($raw) ? $raw : [];
    }

    private function isCedula($text)
    {
        return preg_match('/^[0-9]{5,20}$/', (string) $text) === 1;
    }

    private function normalize($text)
    {
        $text = trim(strtolower((string) $text));
        $text = str_replace(['á', 'é', 'í', 'ó', 'ú', 'ñ'], ['a', 'e', 'i', 'o', 'u', 'n'], $text);
        return preg_replace('/\s+/', ' ', $text);
    }

    private function existsMovilizador($cedula)
    {
        if (isset($this->botRepo) && method_exists($this->botRepo, 'existsMovilizador')) {
            return (bool) $this->botRepo->existsMovilizador($cedula);
        }
        return true;
    }

    private function existsVotante($cedula)
    {
        if (isset($this->botRepo) && method_exists($this->botRepo, 'existsVotante')) {
            return (bool) $this->botRepo->existsVotante($cedula);
        }
        return false;
    }

    private function movilizadorTieneVotantes($cedulaMovilizador)
    {
        if (isset($this->botRepo) && method_exists($this->botRepo, 'movilizadorTieneVotantes')) {
            return (bool) $this->botRepo->movilizadorTieneVotantes($cedulaMovilizador);
        }
        return true;
    }

    private function votantePerteneceAMovilizador($cedulaVotante)
    {
        if (isset($this->botRepo) && method_exists($this->botRepo, 'votantePerteneceAMovilizador')) {
            return (bool) $this->botRepo->votantePerteneceAMovilizador($cedulaVotante);
        }
        return true;
    }

    private function votanteYaVoto()
    {
        if (isset($this->botRepo) && method_exists($this->botRepo, 'votanteYaVoto')) {
            return (bool) $this->botRepo->votanteYaVoto();
        }
        return false;
    }

    private function estadoVotacionEsVotado()
    {
        if (isset($this->botRepo) && method_exists($this->botRepo, 'estadoVotacionEsVotado')) {
            return (bool) $this->botRepo->estadoVotacionEsVotado();
        }
        return false;
    }

    private function okResponse(array $data)
    {
        return [
            'status' => true,
            'codigo' => 1,
            'message' => 'OK',
            'data' => $data,
            'http_code' => REST_Controller::HTTP_OK,
        ];
    }

    private function validationResponse($message, $cycle, array $extra = [])
    {
        return [
            'status' => false,
            'codigo' => 422,
            'message' => $message,
            'data' => ['cycle' => (int) $cycle] + $extra,
            'http_code' => REST_Controller::HTTP_UNPROCESSABLE_ENTITY,
        ];
    }

    private function errorResponse($message, array $data = [])
    {
        return [
            'status' => false,
            'codigo' => 422,
            'message' => $message,
            'data' => $data,
            'http_code' => REST_Controller::HTTP_UNPROCESSABLE_ENTITY,
        ];
    }

    private function sendResponse(array $payload)
    {
        $httpCode = isset($payload['http_code']) ? (int) $payload['http_code'] : REST_Controller::HTTP_OK;
        unset($payload['http_code']);
        $this->set_response($payload, $httpCode);
    }
}
