#!/bin/bash

# Script de construcción para Classic Add-ons Archive v3.0
# Genera paquetes .xpi (Firefox) y .zip (Chrome)

set -e  # Salir si hay errores

echo "=================================================="
echo "  Classic Add-ons Archive - Build Script v3.0"
echo "=================================================="
echo ""

# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Configuración
VERSION="3.0.0"
DIST_DIR="dist"
KEYS_DIR="private-keys"
FIREFOX_PACKAGE="ca-archive-${VERSION}.xpi"
CHROME_PACKAGE="ca-archive-${VERSION}-chrome.zip"
CHROME_CRX="ca-archive-${VERSION}-chrome.crx"
CHROME_KEY="$KEYS_DIR/chrome-extension.pem"
FIREFOX_JWT="$KEYS_DIR/firefox-amo-credentials.json"

# Opciones de línea de comandos
SIGN_MODE=""
for arg in "$@"; do
    case $arg in
        --sign)
            SIGN_MODE="all"
            shift
            ;;
        --sign-chrome)
            SIGN_MODE="chrome"
            shift
            ;;
        --sign-firefox)
            SIGN_MODE="firefox"
            shift
            ;;
        --list|-l)
            LIST_CONTENTS=true
            shift
            ;;
        *)
            ;;
    esac
done

# Archivos a incluir (relativos al directorio raíz)
INCLUDE_FILES=(
    "manifest.json"
    "background.js"
    "content/"
    "skin/"
)

# Archivos a excluir (patrones de exclusión)
EXCLUDE_PATTERNS=(
    "*.git*"
    "*~"
    "*.swp"
    ".DS_Store"
    "Thumbs.db"
    "*.tmp"
    "*.log"
    "*.md"          # Excluir documentación (opcional: comentar para incluir)
    "install.rdf"   # Legacy
    "chrome.manifest" # Legacy
    "bootstrap.js"  # Legacy
    "update.xml"    # Legacy
    "content/db.js" # Legacy (usamos db-webext.js)
    "package.json"
    "package-lock.json"
    "node_modules/"
    "dist/"
)

# Función para imprimir con color
print_status() {
    echo -e "${GREEN}[✓]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[!]${NC} $1"
}

print_error() {
    echo -e "${RED}[✗]${NC} $1"
}

# Verificar que estamos en el directorio correcto
if [ ! -f "manifest.json" ]; then
    print_error "No se encuentra manifest.json"
    print_error "Ejecuta este script desde el directorio raíz del proyecto"
    exit 1
fi

print_status "Directorio de proyecto detectado"

# Crear directorio de distribución
if [ -d "$DIST_DIR" ]; then
    print_warning "Limpiando directorio de distribución existente..."
    rm -rf "$DIST_DIR"
fi

mkdir -p "$DIST_DIR"
print_status "Directorio de distribución creado: $DIST_DIR/"

# Función para construir el comando de exclusión para zip
build_exclude_args() {
    local args=""
    for pattern in "${EXCLUDE_PATTERNS[@]}"; do
        args="$args -x '$pattern'"
    done
    echo "$args"
}

# Construir paquete para Firefox (.xpi)
echo ""
echo "Construyendo paquete para Firefox..."
print_status "Empaquetando archivos..."

# Crear archivo zip temporal
TMP_ZIP="$DIST_DIR/temp.zip"

# Comando de zip con exclusiones
zip -r "$TMP_ZIP" "${INCLUDE_FILES[@]}" \
    -x "${EXCLUDE_PATTERNS[@]}" \
    > /dev/null 2>&1

# Renombrar a .xpi
mv "$TMP_ZIP" "$DIST_DIR/$FIREFOX_PACKAGE"

if [ -f "$DIST_DIR/$FIREFOX_PACKAGE" ]; then
    FIREFOX_SIZE=$(du -h "$DIST_DIR/$FIREFOX_PACKAGE" | cut -f1)
    print_status "Paquete Firefox creado: $FIREFOX_PACKAGE ($FIREFOX_SIZE)"
else
    print_error "Error al crear paquete Firefox"
    exit 1
fi

# Construir paquete para Chrome (.zip)
echo ""
echo "Construyendo paquete para Chrome..."
print_status "Empaquetando archivos..."

zip -r "$DIST_DIR/$CHROME_PACKAGE" "${INCLUDE_FILES[@]}" \
    -x "${EXCLUDE_PATTERNS[@]}" \
    > /dev/null 2>&1

if [ -f "$DIST_DIR/$CHROME_PACKAGE" ]; then
    CHROME_SIZE=$(du -h "$DIST_DIR/$CHROME_PACKAGE" | cut -f1)
    print_status "Paquete Chrome creado: $CHROME_PACKAGE ($CHROME_SIZE)"
else
    print_error "Error al crear paquete Chrome"
    exit 1
fi

# Verificar integridad de los paquetes
echo ""
print_status "Verificando paquetes..."

# Verificar Firefox
if unzip -t "$DIST_DIR/$FIREFOX_PACKAGE" > /dev/null 2>&1; then
    print_status "Paquete Firefox verificado (integridad OK)"
else
    print_error "Paquete Firefox corrupto"
    exit 1
fi

# Verificar Chrome
if unzip -t "$DIST_DIR/$CHROME_PACKAGE" > /dev/null 2>&1; then
    print_status "Paquete Chrome verificado (integridad OK)"
else
    print_error "Paquete Chrome corrupto"
    exit 1
fi

# Firma de paquetes si se solicitó
if [ "$SIGN_MODE" = "firefox" ] || [ "$SIGN_MODE" = "all" ]; then
    echo ""
    echo "=================================================="
    echo "  Firmando paquete Firefox"
    echo "=================================================="
    
    if [ ! -f "$FIREFOX_JWT" ]; then
        print_error "No se encontraron credenciales de Firefox: $FIREFOX_JWT"
        print_warning "Ejecuta: ./scripts/generate-keys.sh"
        exit 1
    fi
    
    # Buscar web-ext: primero en node_modules, luego global
    WEB_EXT=""
    if [ -f "node_modules/.bin/web-ext" ]; then
        WEB_EXT="./node_modules/.bin/web-ext"
        print_status "Usando web-ext local: $WEB_EXT"
    elif command -v npx &> /dev/null; then
        WEB_EXT="npx web-ext"
        print_status "Usando web-ext via npx"
    elif command -v web-ext &> /dev/null; then
        WEB_EXT="web-ext"
        print_status "Usando web-ext global"
    else
        print_error "web-ext no está instalado"
        print_warning "Instalar con: npm install"
        print_warning "O globalmente: npm install -g web-ext"
        exit 1
    fi
    
    print_status "Firmando con AMO..."
    
    # Leer credenciales del JSON
    API_KEY=$(grep -o '"apiKey"[[:space:]]*:[[:space:]]*"[^"]*"' "$FIREFOX_JWT" | cut -d'"' -f4)
    API_SECRET=$(grep -o '"apiSecret"[[:space:]]*:[[:space:]]*"[^"]*"' "$FIREFOX_JWT" | cut -d'"' -f4)
    
    if [ -z "$API_KEY" ] || [ -z "$API_SECRET" ]; then
        print_error "Credenciales de AMO inválidas en $FIREFOX_JWT"
        exit 1
    fi
    
    # Firmar con web-ext
    # Nota: El ID se lee automáticamente de manifest.json, no se pasa como parámetro
    $WEB_EXT sign \
        --source-dir=. \
        --artifacts-dir="$DIST_DIR" \
        --api-key="$API_KEY" \
        --api-secret="$API_SECRET" \
        --channel=unlisted \
        2>&1 | tee "$DIST_DIR/firefox-sign.log"
    
    # Verificar el código de salida
    SIGN_EXIT_CODE=${PIPESTATUS[0]}
    
    if [ $SIGN_EXIT_CODE -eq 0 ]; then
        print_status "Paquete Firefox firmado exitosamente"
        # Buscar el archivo firmado
        SIGNED_XPI=$(ls -t "$DIST_DIR"/*.xpi 2>/dev/null | head -1)
        if [ -f "$SIGNED_XPI" ]; then
            print_status "Archivo firmado: $(basename "$SIGNED_XPI")"
        fi
    else
        print_error "Error al firmar paquete Firefox (código: $SIGN_EXIT_CODE)"
        print_warning "Revisa: $DIST_DIR/firefox-sign.log"
        exit $SIGN_EXIT_CODE
    fi
fi

if [ "$SIGN_MODE" = "chrome" ] || [ "$SIGN_MODE" = "all" ]; then
    echo ""
    echo "=================================================="
    echo "  Firmando paquete Chrome"
    echo "=================================================="
    
    if [ ! -f "$CHROME_KEY" ]; then
        print_error "No se encontró clave de Chrome: $CHROME_KEY"
        print_warning "Ejecuta: ./scripts/generate-keys.sh"
        exit 1
    fi
    
    if ! command -v google-chrome &> /dev/null && ! command -v chromium &> /dev/null; then
        print_warning "Chrome/Chromium no encontrado, usando método alternativo..."
        
        # Método alternativo: crear .crx manualmente
        print_status "Generando .crx con openssl..."
        
        # Extraer clave pública
        openssl rsa -in "$CHROME_KEY" -pubout -outform DER > "$DIST_DIR/public.der" 2>/dev/null
        
        # Crear firma
        openssl dgst -sha256 -sign "$CHROME_KEY" -out "$DIST_DIR/signature.bin" "$DIST_DIR/$CHROME_PACKAGE"
        
        # Leer tamaños
        pub_size=$(wc -c < "$DIST_DIR/public.der")
        sig_size=$(wc -c < "$DIST_DIR/signature.bin")
        
        # Crear header CRX3
        (
            printf "Cr24"  # Magic number
            printf '\x03\x00\x00\x00'  # Version 3
            printf "$(printf '%08x' $pub_size | sed 's/\(..\)/\\x\1/g' | tac -s'\\')"  # Public key length (little endian)
            printf "$(printf '%08x' $sig_size | sed 's/\(..\)/\\x\1/g' | tac -s'\\')"  # Signature length (little endian)
            cat "$DIST_DIR/public.der"
            cat "$DIST_DIR/signature.bin"
            cat "$DIST_DIR/$CHROME_PACKAGE"
        ) > "$DIST_DIR/$CHROME_CRX"
        
        # Limpiar archivos temporales
        rm -f "$DIST_DIR/public.der" "$DIST_DIR/signature.bin"
        
        if [ -f "$DIST_DIR/$CHROME_CRX" ]; then
            CRX_SIZE=$(du -h "$DIST_DIR/$CHROME_CRX" | cut -f1)
            print_status "Paquete Chrome firmado: $CHROME_CRX ($CRX_SIZE)"
            
            # Calcular hash
            CRX_HASH=$(sha256sum "$DIST_DIR/$CHROME_CRX" | cut -d' ' -f1)
            echo "$CRX_HASH" > "$DIST_DIR/${CHROME_CRX}.sha256"
            print_status "Hash SHA256 guardado"
        else
            print_error "Error al crear .crx"
        fi
    else
        print_status "Empaquetando con Chrome..."
        
        # Usar Chrome para empaquetar
        CHROME_BIN=$(command -v google-chrome || command -v chromium)
        
        "$CHROME_BIN" --pack-extension=. --pack-extension-key="$CHROME_KEY" --no-message-box 2>/dev/null
        
        if [ -f "$(basename $(pwd)).crx" ]; then
            mv "$(basename $(pwd)).crx" "$DIST_DIR/$CHROME_CRX"
            print_status "Paquete Chrome firmado: $CHROME_CRX"
        else
            print_error "Error al firmar con Chrome"
        fi
    fi
    
    # Calcular Extension ID
    if [ -f "$CHROME_KEY" ]; then
        CHROME_ID=$(openssl rsa -in "$CHROME_KEY" -pubout -outform DER 2>/dev/null | \
                    openssl dgst -sha256 -binary | \
                    head -c 16 | \
                    od -An -tx1 | \
                    tr -d ' \n' | \
                    tr '0-9a-f' 'a-p')
        echo "$CHROME_ID" > "$DIST_DIR/chrome-extension-id.txt"
        print_status "Extension ID: $CHROME_ID"
    fi
fi

# Listar contenido (opcional)
if [ "$LIST_CONTENTS" = true ]; then
    echo ""
    echo "Contenido del paquete Firefox:"
    unzip -l "$DIST_DIR/$FIREFOX_PACKAGE"
fi

# Resumen final
echo ""
echo "=================================================="
echo "  ✨ Build completado exitosamente"
echo "=================================================="
echo ""
echo "Paquetes generados en: $DIST_DIR/"
echo ""
echo "  Firefox:  $FIREFOX_PACKAGE ($FIREFOX_SIZE)"
echo "  Chrome:   $CHROME_PACKAGE ($CHROME_SIZE)"

if [ "$SIGN_MODE" = "chrome" ] || [ "$SIGN_MODE" = "all" ]; then
    if [ -f "$DIST_DIR/$CHROME_CRX" ]; then
        CRX_SIZE=$(du -h "$DIST_DIR/$CHROME_CRX" | cut -f1)
        echo "  Chrome (firmado): $CHROME_CRX ($CRX_SIZE)"
    fi
fi

echo ""

if [ -z "$SIGN_MODE" ]; then
    echo "  ℹ️  Paquetes sin firmar. Para firmar usa:"
    echo "     ./build.sh --sign           # Firmar ambos"
    echo "     ./build.sh --sign-firefox   # Solo Firefox"
    echo "     ./build.sh --sign-chrome    # Solo Chrome"
    echo ""
fi

echo "Próximos pasos:"
echo ""

if [ -n "$SIGN_MODE" ]; then
    echo "  Paquetes firmados ✓"
    echo ""
    echo "  Para publicar:"
    if [ "$SIGN_MODE" = "firefox" ] || [ "$SIGN_MODE" = "all" ]; then
        echo "    Firefox AMO: El archivo firmado está listo para subir"
        echo "    https://addons.mozilla.org/developers/"
    fi
    if [ "$SIGN_MODE" = "chrome" ] || [ "$SIGN_MODE" = "all" ]; then
        echo "    Chrome Web Store: Sube el archivo .zip (no .crx)"
        echo "    https://chrome.google.com/webstore/devconsole"
    fi
else
    echo "  Firefox:"
    echo "    1. Ir a about:debugging#/runtime/this-firefox"
    echo "    2. Click en 'Cargar complemento temporal'"
    echo "    3. Seleccionar: $DIST_DIR/$FIREFOX_PACKAGE"
    echo ""
    echo "  Chrome:"
    echo "    1. Ir a chrome://extensions/"
    echo "    2. Activar 'Modo de desarrollador'"
    echo "    3. Click en 'Cargar extensión sin empaquetar'"
    echo "    4. Extraer y seleccionar la carpeta de $CHROME_PACKAGE"
fi

echo ""
echo "=================================================="

exit 0
