<?php
// Archivo includes/imap_lib.php con validación para msgno = 0

declare(strict_types=1);

require_once __DIR__ . '/db.php';
require_once __DIR__ . '/crypto.php';

// Construcción del mailbox IMAP
function imap_mailbox_string(array $imap): string {
  $host = $imap['host'] ?? 'imap.gmail.com';
  $port = (int)($imap['port'] ?? 993);
  $flags = $imap['flags'] ?? '';
  if (!$flags) {
    $enc = strtolower($imap['encryption'] ?? 'ssl');
    if ($enc === 'ssl') $flags = '/imap/ssl/validate-cert';
    elseif ($enc === 'tls') $flags = '/imap/tls/validate-cert';
    else $flags = '/imap/novalidate-cert';
  }
  return sprintf('{%s:%d%s}', $host, $port, $flags);
}

// Obtiene la parte del cuerpo con manejo de msgno inválido
function get_part($stream, $uid, $partNumber, $encoding) {
    $msgno = imap_msgno($stream, (int)$uid);
    if ($msgno === 0) {
        error_log("imap_lib.php: UID $uid no corresponde a número de mensaje válido.");
        return ''; // Mensaje no encontrado, evitar error
    }
    $text = @imap_fetchbody($stream, $msgno, $partNumber);
    if ($text === false || $text === null) {
        return '';
    }
    switch ($encoding) {
        case 3: $text = base64_decode($text); break;
        case 4: $text = quoted_printable_decode($text); break;
    }
    return $text;
}

function get_message_body_html($stream, $uid, $structure, $partNumber = '') {
    $body = '';
    if (!isset($structure->parts)) {
        if (strtolower($structure->subtype) === 'html') {
            $body = get_part($stream, $uid, $partNumber === '' ? '1' : $partNumber, $structure->encoding);
        }
    } else {
        foreach ($structure->parts as $index => $subStruct) {
            $prefix = $partNumber === '' ? '' : $partNumber . '.';
            if (strtolower($subStruct->subtype) === 'html') {
                $body .= get_part($stream, $uid, $prefix . ($index + 1), $subStruct->encoding);
            }
        }
    }
    return $body;
}

function decode_subject($subjectRaw) {
    $subjectParts = imap_mime_header_decode($subjectRaw);
    $subject = '';
    foreach ($subjectParts as $part) {
        $charset = $part->charset;
        $text = $part->text;
        if ($charset && $charset != 'default') {
            $text = iconv($charset, 'UTF-8//TRANSLIT', $text);
        }
        $subject .= $text;
    }
    return $subject;
}

function get_disney_otp_code($htmlBody) {
    if (!$htmlBody) return null;
    if (preg_match('/<td[^>]*font-size:\s*28px[^>]*>\s*(\d{6})\s*<\/td>/i', $htmlBody, $matches)) {
        return $matches[1];
    }
    return null;
}

function extract_verification_links_netflix($htmlBody) {
    $links = [];
    if (!$htmlBody) return $links;
    $dom = new DOMDocument();
    @$dom->loadHTML($htmlBody);
    foreach ($dom->getElementsByTagName('a') as $a) {
        $href = $a->getAttribute('href');
        $text = trim($a->textContent);
        if (preg_match('/netflix\.com/i', $href) && preg_match('/(verify|confirm|action|token|login|security)/i', $href . ' ' . $text)) {
            $links[] = ['url' => $href, 'text' => $text ?: $href];
        }
    }
    return $links;
}


function get_prime_otp_code($htmlBody) {
    if (!$htmlBody) return null;

    $text = strip_tags($htmlBody);

    // Patrón principal para Prime Video: "usa el siguiente código: 123456"
    if (preg_match('/usa el siguiente código[\D]*?(\d{6})/i', $text, $matches)) {
        return $matches[1];
    }

    // Otros patrones comunes para OTP 6 dígitos con contexto
    $patternContext = '/(intento de inicio de sesión|código de verificación|verificación|ingreso|confirmar)/i';
    if (preg_match($patternContext, $text)) {
        if (preg_match('/(?:tu código de verificación es|tu código es|código de verificación|código otp).*?(\d{6})/i', $text, $matches)) {
            return $matches[1];
        }
        if (preg_match('/\b\d{6}\b/', $text, $matches)) {
            return $matches[0];
        }
    }

    return null;
}

function process_disney($stream, $uids, $account) {
    foreach ($uids as $uid) {
        $overview = @imap_fetch_overview($stream, (string)$uid, FT_UID)[0] ?? null;
        if (!$overview) continue;
        $fromHeader = $overview->from ?? '';
        if (!preg_match('/disneyplus\.com|disney\.com/i', $fromHeader)) continue;
        $msgno = imap_msgno($stream, (int)$uid);
        if ($msgno === 0) continue;
        $structure = imap_fetchstructure($stream, $msgno);
        $htmlBody = get_message_body_html($stream, (string)$uid, $structure);
        $code = get_disney_otp_code($htmlBody);
        if ($code !== null) {
            $headerInfo = imap_headerinfo($stream, $msgno);
            $toEmail = $headerInfo->to[0]->mailbox . '@' . $headerInfo->to[0]->host;
            if (strcasecmp($account, $toEmail) !== 0) {
                throw new Exception('No has solicitado código para esta cuenta.');
            }
            return [
                'code'    => $code,
                'subject' => decode_subject($overview->subject ?? ''),
                'from'    => $fromHeader,
                'to'      => $toEmail,
                'date'    => $overview->date ?? '',
            ];
        }
    }
    return null;
}

function get_netflix_otp_code($htmlBody) {
    if (!$htmlBody) return null;
    $text = strip_tags($htmlBody);
    $text = html_entity_decode($text);
    $text = trim($text);

    // Busca código OTP en línea sola
    if (preg_match('/^\s*(\d{4,6})\s*$/m', $text, $matches)) {
        return $matches[1];
    }

    // Busca después del texto clave
    if (preg_match('/ingresa este código para iniciar sesión.*?(\d{4,6})/is', $text, $matches)) {
        return $matches[1];
    }

    return null;
}


function process_netflix($stream, $uids, $account) {
    foreach ($uids as $uid) {
        $overview = @imap_fetch_overview($stream, (string)$uid, FT_UID)[0] ?? null;
        if (!$overview) continue;

        $fromHeader = $overview->from ?? '';
        if (!preg_match('/netflix\.com/i', $fromHeader)) continue;

        $msgno = imap_msgno($stream, (int)$uid);
        if ($msgno === 0) continue;

        $structure = imap_fetchstructure($stream, $msgno);
        $htmlBody = get_message_body_html($stream, (string)$uid, $structure);

        $headerInfo = imap_headerinfo($stream, $msgno);
        $toEmail = $headerInfo->to[0]->mailbox . '@' . $headerInfo->to[0]->host;
        if (strcasecmp($account, $toEmail) !== 0) continue;

        $code = get_netflix_otp_code($htmlBody);
        if ($code !== null) {
            return [
                'code'    => $code,
                'subject' => decode_subject($overview->subject ?? ''),
                'from'    => $fromHeader,
                'to'      => $toEmail,
                'date'    => $overview->date ?? '',
            ];
        }

        $links = extract_verification_links_netflix($htmlBody);
        if (!empty($links)) {
            return [
                'links'   => $links,
                'subject' => decode_subject($overview->subject ?? ''),
                'from'    => $fromHeader,
                'to'      => $toEmail,
                'date'    => $overview->date ?? '',
            ];
        }
    }
    return null;
}

function process_prime($stream, $uids, $account) {
    foreach ($uids as $uid) {
        $overview = @imap_fetch_overview($stream, (string)$uid, FT_UID)[0] ?? null;
        if (!$overview) continue;

        $fromHeader = $overview->from ?? '';
        // Soporta amazon.com y primevideo.com como remitentes
        if (!preg_match('/amazon\.com|primevideo\.com/i', $fromHeader)) continue;

        $msgno = imap_msgno($stream, (int)$uid);
        if ($msgno === 0) continue;

        $structure = imap_fetchstructure($stream, $msgno);
        $htmlBody = get_message_body_html($stream, (string)$uid, $structure);

        // Extrae el código OTP con patrón que busca "usa el siguiente código:"
        $code = null;
        if ($htmlBody) {
            $textBody = strip_tags($htmlBody);
            if (preg_match('/usa el siguiente código[\D]*?(\d{6})/i', $textBody, $matches)) {
                $code = $matches[1];
            }
        }

        // Fallback: usa la función genérica para otros formatos
        if ($code === null) {
            $code = get_prime_otp_code($htmlBody);
        }
        if ($code === null) continue;

        $headerInfo = imap_headerinfo($stream, $msgno);
        $toEmail = $headerInfo->to[0]->mailbox . '@' . $headerInfo->to[0]->host;

        if (strcasecmp($account, $toEmail) !== 0) {
            throw new Exception('No has solicitado código para esta cuenta.');
        }

        $subject = decode_subject($overview->subject ?? '');
        $allText = $subject . ' ' . strip_tags($htmlBody);

        if (preg_match('/recuperaci[oó]n|restablecimiento|reset|cambio|cambiar.*contrase(?:ñ|n)a/i', $allText)) {
            throw new Exception('No puedes hacer este proceso con correos de recuperación de contraseña.');
        }

        if (preg_match('/Intento de inicio de sesión|verificación|código/i', $allText)) {
            return [
                'code'    => $code,
                'subject' => $subject,
                'from'    => $fromHeader,
                'to'      => $toEmail,
                'date'    => $overview->date ?? '',
            ];
        }
    }
    return null;
}