-- Extensões para KVS Database
-- Este arquivo contém toda a lógica de extensão que será carregada pelo Rust

-- Funções de validação de CPF
local function validate_cpf(cpf)
    -- Remove caracteres não numéricos
    cpf = cpf:gsub("%D", "")
    
    -- Verifica se CPF tem 11 dígitos
    if #cpf ~= 11 then
        return false, "CPF deve ter exatamente 11 dígitos"
    end
    
    -- Verifica se todos os dígitos são iguais (CPF inválido)
    if cpf:match("^(%d)%1*$") then
        return false, "CPF não pode ter todos os dígitos iguais"
    end
    
    -- Calcula o primeiro dígito verificador
    local sum = 0
    for i = 1, 9 do
        sum = sum + tonumber(cpf:sub(i, i)) * (11 - i)
    end
    local remainder = sum % 11
    local first_digit = (remainder < 2) and 0 or (11 - remainder)
    
    -- Calcula o segundo dígito verificador
    sum = 0
    for i = 1, 10 do
        sum = sum + tonumber(cpf:sub(i, i)) * (12 - i)
    end
    remainder = sum % 11
    local second_digit = (remainder < 2) and 0 or (11 - remainder)
    
    -- Verifica se os dígitos calculados correspondem aos fornecidos
    local provided_first = tonumber(cpf:sub(10, 10))
    local provided_second = tonumber(cpf:sub(11, 11))
    
    if first_digit == provided_first and second_digit == provided_second then
        return true, nil
    else
        return false, "Dígitos verificadores do CPF são inválidos"
    end
end

local function format_cpf(cpf)
    -- Remove caracteres não numéricos e formata
    cpf = cpf:gsub("%D", "")
    return cpf:sub(1,3) .. "." .. cpf:sub(4,6) .. "." .. cpf:sub(7,9) .. "-" .. cpf:sub(10,11)
end

-- Funções de validação de data
local function validate_iso_date(date_str)
    -- Verifica se a data está no formato ISO8601: YYYY-MM-DD (deve ser exatamente este formato)
    local year, month, day = date_str:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
    
    if not year or not month or not day then
        return false, "Data deve estar no formato ISO8601: YYYY-MM-DD"
    end
    
    year, month, day = tonumber(year), tonumber(month), tonumber(day)
    
    -- Validação básica
    if year < 1900 or year > 2100 then
        return false, "Ano inválido (deve ser entre 1900 e 2100)"
    end
    
    if month < 1 or month > 12 then
        return false, "Mês inválido (deve ser entre 01 e 12)"
    end
    
    if day < 1 or day > 31 then
        return false, "Dia inválido (deve ser entre 01 e 31)"
    end
    
    -- Validação mais específica do mês
    local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    
    -- Verifica se é ano bissexto
    if month == 2 and ((year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0)) then
        days_in_month[2] = 29
    end
    
    if day > days_in_month[month] then
        return false, "Dia inválido para o mês " .. month .. " (máximo " .. days_in_month[month] .. " dias)"
    end
    
    return true, nil
end

local function format_date(date_str)
    -- Converte YYYY-MM-DD para DD/MM/YYYY
    local year, month, day = date_str:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
    if not year or not month or not day then
        return date_str -- Retorna original se formato estiver errado
    end
    return day .. "/" .. month .. "/" .. year
end

-- Funções principais chamadas pelo Rust
function handle_add(key, value)
    -- Verifica se a chave corresponde ao padrão CPF
    if key:match("^cpf_") then
        local valid, error_msg = validate_cpf(value)
        if valid then
            return {
                success = true,
                value = value, -- Armazena valor original para formatação posterior
                error = nil
            }
        else
            return {
                success = false,
                value = nil,
                error = error_msg
            }
        end
    end
    
    -- Verifica se a chave corresponde ao padrão data
    if key:match("^data_") then
        local valid, error_msg = validate_iso_date(value)
        if valid then
            return {
                success = true,
                value = value, -- Armazena valor original para formatação posterior
                error = nil
            }
        else
            return {
                success = false,
                value = nil,
                error = error_msg
            }
        end
    end
    
    -- Caso padrão: sem processamento especial
    return {
        success = true,
        value = value,
        error = nil
    }
end

function handle_get(key, stored_value)
    -- Verifica se a chave corresponde ao padrão CPF
    if key:match("^cpf_") then
        return {
            success = true,
            value = format_cpf(stored_value),
            error = nil
        }
    end
    
    -- Verifica se a chave corresponde ao padrão data
    if key:match("^data_") then
        return {
            success = true,
            value = format_date(stored_value),
            error = nil
        }
    end
    
    -- Caso padrão: retorna valor armazenado como está
    return {
        success = true,
        value = stored_value,
        error = nil
    }
end
