package main

import (
    "bufio"
    "flag"
    "fmt"
    "net/http"
    "os"
    "strings"
    "time"
)

func extractAnchorText(line string) (string, bool) {
    // Busca el texto entre > y < del primer <a ...>...</a>
    gt := strings.Index(line, ">")
    if gt == -1 {
        return "", false
    }
    lt := strings.Index(line[gt+1:], "<")
    if lt == -1 {
        return "", false
    }
    text := line[gt+1 : gt+1+lt]
    text = strings.TrimSpace(text)
    if text == "" {
        return "", false
    }
    return text, true
}

func main() {
    // Flags
    maxResults := flag.Int("max", 30, "Número máximo de resultados a mostrar")
    prefix := flag.Bool("prefix", false, "Buscar por prefijo en lugar de subcadena")
    timeout := flag.Duration("timeout", 20*time.Second, "Timeout de la petición HTTP (e.g., 10s, 2m)")
    noColor := flag.Bool("nocolor", false, "Desactivar iconos/colores")
    flag.Parse()

    if flag.NArg() < 1 {
        fmt.Println("Uso: pip_busca [opciones] <cadena_busqueda>")
        fmt.Println("Opciones:")
        fmt.Println("  -max N        Limitar el número de resultados (por defecto 30)")
        fmt.Println("  -prefix       Coincidencia por prefijo (más rápida si buscas por inicio)")
        fmt.Println("  -timeout DUR  Timeout de HTTP (por defecto 20s)")
        fmt.Println("  -nocolor      Desactiva iconos/colores en salida")
        os.Exit(1)
    }

    query := strings.ToLower(flag.Arg(0))
    url := "https://pypi.org/simple/"

    client := &http.Client{Timeout: *timeout}
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        fmt.Fprintf(os.Stderr, "❌ Error creando petición: %v\n", err)
        os.Exit(1)
    }
    req.Header.Set("User-Agent", "pip_busca-go/1.0 (+https://pypi.org)")
    req.Header.Set("Accept", "text/html")

    resp, err := client.Do(req)
    if err != nil {
        fmt.Fprintf(os.Stderr, "❌ Error conectando con PyPI: %v\n", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        fmt.Fprintf(os.Stderr, "❌ Respuesta HTTP no OK: %s\n", resp.Status)
        os.Exit(1)
    }

    if !*noColor {
        fmt.Printf("🔍 Buscando: %s\n\n", query)
    } else {
        fmt.Printf("Buscando: %s\n\n", query)
    }

    scanner := bufio.NewScanner(resp.Body)
    // Aumenta el buffer por si alguna línea es grande (aunque en /simple suele ser pequeño)
    const maxLine = 1024 * 1024 // 1 MiB
    buf := make([]byte, 64*1024)
    scanner.Buffer(buf, maxLine)

    encontrados := 0
    queryStarted := false // para modo -prefix: romper cuando superemos el bloque

    for scanner.Scan() {
        line := scanner.Text()
        // Normalizamos a minúsculas para buscar
        lower := strings.ToLower(line)

        // Solo nos interesan líneas con anclas
        if !strings.Contains(lower, "<a ") || !strings.Contains(lower, "</a>") {
            continue
        }

        name, ok := extractAnchorText(line)
        if !ok {
            continue
        }
        nameLower := strings.ToLower(name)

        match := false
        if *prefix {
            // Coincidencia por prefijo
            if strings.HasPrefix(nameLower, query) {
                match = true
                queryStarted = true
            } else if queryStarted {
                // /simple/ está ordenado; si ya pasamos el bloque del prefijo, podemos cortar.
                // Cuando el nombre actual ya no empieza por el prefijo y ya habíamos empezado
                // a encontrar coincidencias, significa que hemos superado la zona.
                break
            }
        } else {
            // Coincidencia por subcadena
            if strings.Contains(nameLower, query) {
                match = true
            }
        }

        if match {
            if !*noColor {
                fmt.Printf("📦 %s\n", name)
            } else {
                fmt.Println(name)
            }
            encontrados++
            if encontrados >= *maxResults {
                break
            }
        }
    }

    if err := scanner.Err(); err != nil {
        fmt.Fprintf(os.Stderr, "⚠️  Aviso: error leyendo la respuesta: %v\n", err)
    }

    if encontrados == 0 {
        fmt.Println("❌ No se encontraron paquetes.")
    }
}
