<?php

if (!function_exists('str_contains')) {
    function str_contains($haystack, $needle)
    {
        return $needle === '' || strpos((string) $haystack, (string) $needle) !== false;
    }
}

if (!function_exists('str_starts_with')) {
    function str_starts_with($haystack, $needle)
    {
        return substr((string) $haystack, 0, strlen((string) $needle)) === (string) $needle;
    }
}

function normalizeDateInput($value)
{
    $value = trim($value);
    if ($value === '') {
        return null;
    }

    $date = DateTime::createFromFormat('Y-m-d', $value);
    $errors = DateTime::getLastErrors();
    $warningCount = is_array($errors) ? (int) ($errors['warning_count'] ?? 0) : 0;
    $errorCount = is_array($errors) ? (int) ($errors['error_count'] ?? 0) : 0;

    if (!$date || $warningCount > 0 || $errorCount > 0 || $date->format('Y-m-d') !== $value) {
        return null;
    }

    return $value;
}

function normalizeSubmittedDate($value)
{
    $value = trim((string) $value);
    if ($value === '') {
        return null;
    }

    $date = null;
    if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $value) === 1) {
        $date = DateTime::createFromFormat('d/m/Y', $value);
    } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) === 1) {
        $date = DateTime::createFromFormat('Y-m-d', $value);
    }

    if (!$date) {
        return null;
    }

    return $date->format('Y-m-d');
}

function normalizeCategoria($categoria)
{
    $categoria = trim((string) $categoria);
    if ($categoria === '') {
        return null;
    }

    $categoriaLower = function_exists('mb_strtolower')
        ? mb_strtolower($categoria, 'UTF-8')
        : strtolower($categoria);

    return $categoriaLower === 'sem categoria' ? null : $categoria;
}

function storedFileDisplayName($value)
{
    $value = trim($value);
    if ($value === '') {
        return '';
    }

    $path = parse_url($value, PHP_URL_PATH);
    $basename = basename((string) ($path ?: $value));
    return $basename === '' || $basename === '.' || $basename === '/' ? $value : $basename;
}

function resolveStoredLocalFilePath($value, $baseDir = null)
{
    $value = trim($value);
    if ($value === '') {
        return null;
    }

    $baseDir = $baseDir ?? __DIR__;
    $baseReal = realpath($baseDir) ?: $baseDir;

    if (preg_match('#^https?://#i', $value)) {
        return null;
    }

    $path = parse_url($value, PHP_URL_PATH);
    $relative = str_replace(["\0", '\\'], ['', '/'], (string) ($path ?: $value));
    $relative = ltrim($relative, '/');

    if ($relative === '' || str_contains($relative, '../')) {
        return null;
    }

    $candidate = $baseReal . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relative);
    $candidateReal = realpath($candidate);

    if ($candidateReal !== false) {
        $basePrefix = rtrim($baseReal, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
        return str_starts_with($candidateReal, $basePrefix) ? $candidateReal : null;
    }

    if (!str_starts_with($relative, 'uploads/')) {
        return null;
    }

    return $candidate;
}

function insertRowFromArray(PDO $pdo, $table, array $row)
{
    if ($row === []) {
        throw new InvalidArgumentException('Nenhum dado informado para inserção.');
    }

    $columns = array_keys($row);
    $quotedColumns = array_map(function ($column) {
        return '`' . str_replace('`', '``', $column) . '`';
    }, $columns);
    $placeholders = array_map(function ($column) {
        return ':' . $column;
    }, $columns);

    $sql = sprintf(
        'INSERT INTO `%s` (%s) VALUES (%s)',
        str_replace('`', '``', $table),
        implode(', ', $quotedColumns),
        implode(', ', $placeholders)
    );

    $stmt = $pdo->prepare($sql);
    foreach ($row as $column => $value) {
        if ($value === null) {
            $stmt->bindValue(':' . $column, null, PDO::PARAM_NULL);
        } else {
            $stmt->bindValue(':' . $column, $value);
        }
    }
    $stmt->execute();

    return (int) $pdo->lastInsertId();
}

function filterDuplicableRow(array $row, $exclude = array('id', 'created_at', 'updated_at', 'deleted_at', 'uuid', 'token', 'public_token', 'slug', 'hash'))
{
    foreach (array_unique($exclude) as $column) {
        unset($row[$column]);
    }

    return $row;
}

function truncateText($value, $maxLength)
{
    $value = trim($value);
    if ($maxLength <= 0) {
        return '';
    }

    if (function_exists('mb_substr')) {
        return mb_substr($value, 0, $maxLength, 'UTF-8');
    }

    return substr($value, 0, $maxLength);
}

function splitOptions($opcoes)
{
    if ($opcoes === null || trim($opcoes) === '') {
        return [];
    }

    return array_values(array_filter(array_map(function ($item) {
        return trim($item);
    }, explode(',', $opcoes)), function ($item) {
        return $item !== '';
    }));
}

function escapeLike(string $value, string $escapeChar = '\\'): string
{
    return str_replace(
        [$escapeChar, '%', '_'],
        [$escapeChar . $escapeChar, $escapeChar . '%', $escapeChar . '_'],
        $value
    );
}

function digitsOnly($value)
{
    return preg_replace('/\D+/', '', (string) $value) ?? '';
}

function isValidCpf($value)
{
    $cpf = digitsOnly($value);
    if (strlen($cpf) !== 11 || preg_match('/^(\d)\1{10}$/', $cpf) === 1) {
        return false;
    }

    for ($t = 9; $t < 11; $t++) {
        $sum = 0;
        for ($i = 0; $i < $t; $i++) {
            $sum += ((int) $cpf[$i]) * (($t + 1) - $i);
        }
        $digit = ((10 * $sum) % 11) % 10;
        if ((int) $cpf[$t] !== $digit) {
            return false;
        }
    }

    return true;
}

function isValidCnpj($value)
{
    $cnpj = digitsOnly($value);
    if (strlen($cnpj) !== 14 || preg_match('/^(\d)\1{13}$/', $cnpj) === 1) {
        return false;
    }

    $weights1 = [5,4,3,2,9,8,7,6,5,4,3,2];
    $weights2 = [6,5,4,3,2,9,8,7,6,5,4,3,2];

    $sum = 0;
    for ($i = 0; $i < 12; $i++) {
        $sum += ((int) $cnpj[$i]) * $weights1[$i];
    }
    $rest = $sum % 11;
    $digit1 = $rest < 2 ? 0 : 11 - $rest;
    if ((int) $cnpj[12] !== $digit1) {
        return false;
    }

    $sum = 0;
    for ($i = 0; $i < 13; $i++) {
        $sum += ((int) $cnpj[$i]) * $weights2[$i];
    }
    $rest = $sum % 11;
    $digit2 = $rest < 2 ? 0 : 11 - $rest;

    return (int) $cnpj[13] === $digit2;
}
