#!/bin/bash
# ============================================================
# TOTES SAC - Script de Corrección de Bugs
# Fecha: 2026-06-09
# 
# INSTRUCCIONES:
# 1. Copia este archivo a la RAÍZ de tu proyecto Totes en QA
# 2. Ejecuta: chmod +x apply-bugfixes.sh && ./apply-bugfixes.sh
# 3. Luego ejecuta: bun run db:push && npx tsx prisma/seed-admin.ts
# 4. Reinicia el servicio: bun dev start
# ============================================================

set -e

echo "🔧 Aplicando correcciones de bugs a Totes SAC..."
echo ""

# Verificar que estamos en la raíz del proyecto
if [ ! -f "package.json" ]; then
  echo "❌ Error: Ejecuta este script desde la raíz del proyecto (donde está package.json)"
  exit 1
fi

echo "✅ Directorio del proyecto verificado"

# ============================================================
# BUG 1: findUnique → findFirst en customers/[id]
# Causa: error 500 al ver/editar/desactivar clientes
# ============================================================
echo ""
echo "📝 [1/13] Corrigiendo customers/[id]/route.ts (findUnique → findFirst)..."

cat > src/app/api/users/customers/\[id\]/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'
import { hashPassword } from '@/lib/auth'

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth(['SUPERVISOR', 'MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { id } = await params

    const customer = await db.user.findFirst({
      where: { id, role: 'CUSTOMER' },
      select: {
        id: true,
        email: true,
        name: true,
        phone: true,
        isActive: true,
        createdAt: true,
        _count: { select: { reviews: true } },
      },
    })

    if (!customer) {
      return NextResponse.json(
        { error: 'Cliente no encontrado' },
        { status: 404 }
      )
    }

    return NextResponse.json({ customer })
  } catch (error) {
    console.error('Error al obtener cliente:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}

export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth(['SUPERVISOR', 'MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { id } = await params
    const body = await request.json()
    const { name, phone, email, password } = body

    const customer = await db.user.findFirst({
      where: { id, role: 'CUSTOMER' },
    })

    if (!customer) {
      return NextResponse.json(
        { error: 'Cliente no encontrado' },
        { status: 404 }
      )
    }

    const updateData: { name?: string; phone?: string | null; email?: string; passwordHash?: string } = {}

    if (name !== undefined) updateData.name = name.trim()
    if (phone !== undefined) updateData.phone = phone?.trim() || null
    if (email !== undefined) {
      const trimmedEmail = email.toLowerCase().trim()
      // Check email uniqueness if changing
      if (trimmedEmail !== customer.email) {
        const existing = await db.user.findUnique({ where: { email: trimmedEmail } })
        if (existing) {
          return NextResponse.json(
            { error: 'Ya existe una cuenta con este email' },
            { status: 409 }
          )
        }
      }
      updateData.email = trimmedEmail
    }
    if (password) {
      if (password.length < 6) {
        return NextResponse.json(
          { error: 'La contraseña debe tener al menos 6 caracteres' },
          { status: 400 }
        )
      }
      updateData.passwordHash = await hashPassword(password)
    }

    const updated = await db.user.update({
      where: { id },
      data: updateData,
      select: {
        id: true,
        email: true,
        name: true,
        phone: true,
        isActive: true,
        createdAt: true,
      },
    })

    return NextResponse.json({ customer: updated })
  } catch (error) {
    console.error('Error al actualizar cliente:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}

export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth(['MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { id } = await params

    const customer = await db.user.findFirst({
      where: { id, role: 'CUSTOMER' },
    })

    if (!customer) {
      return NextResponse.json(
        { error: 'Cliente no encontrado' },
        { status: 404 }
      )
    }

    // Deactivate instead of deleting
    const updated = await db.user.update({
      where: { id },
      data: { isActive: false },
      select: {
        id: true,
        email: true,
        name: true,
        isActive: true,
      },
    })

    return NextResponse.json({ customer: updated })
  } catch (error) {
    console.error('Error al desactivar cliente:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ customers/[id]/route.ts corregido"

# ============================================================
# BUG 2: Lista de customers incluye inactivos
# ============================================================
echo "📝 [2/13] Corrigiendo customers/route.ts (filtrar inactivos)..."

cat > src/app/api/users/customers/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'
import { hashPassword } from '@/lib/auth'
import { Prisma } from '@prisma/client'

export async function GET(request: NextRequest) {
  try {
    const authResult = await requireAuth(['SUPERVISOR', 'MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { searchParams } = new URL(request.url)
    const search = searchParams.get('search')
    const page = parseInt(searchParams.get('page') || '1')
    const limit = parseInt(searchParams.get('limit') || '20')

    const where: Prisma.UserWhereInput = { role: 'CUSTOMER', isActive: true }

    if (search) {
      where.OR = [
        { name: { contains: search } },
        { email: { contains: search } },
        { phone: { contains: search } },
        { company: { contains: search } },
      ]
    }

    const [customers, total] = await Promise.all([
      db.user.findMany({
        where,
        select: {
          id: true,
          email: true,
          name: true,
          company: true,
          phone: true,
          isActive: true,
          createdAt: true,
          assignedBy: { select: { id: true, name: true } },
          _count: { select: { reviews: true } },
        },
        orderBy: { createdAt: 'desc' },
        skip: (page - 1) * limit,
        take: limit,
      }),
      db.user.count({ where }),
    ])

    return NextResponse.json({
      customers,
      pagination: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    })
  } catch (error) {
    console.error('Error al listar clientes:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}

export async function POST(request: NextRequest) {
  try {
    const authResult = await requireAuth(['SUPERVISOR', 'MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult
    const body = await request.json()
    const { email, name, phone, password, company } = body

    if (!email || !name || !password) {
      return NextResponse.json(
        { error: 'Email, nombre y contraseña son requeridos' },
        { status: 400 }
      )
    }

    if (password.length < 6) {
      return NextResponse.json(
        { error: 'La contraseña debe tener al menos 6 caracteres' },
        { status: 400 }
      )
    }

    const existingUser = await db.user.findUnique({
      where: { email: email.toLowerCase().trim() },
    })

    if (existingUser) {
      return NextResponse.json(
        { error: 'Ya existe una cuenta con este email' },
        { status: 409 }
      )
    }

    const passwordHash = await hashPassword(password)

    const customer = await db.user.create({
      data: {
        email: email.toLowerCase().trim(),
        name: name.trim(),
        company: company?.trim() || null,
        phone: phone?.trim() || null,
        passwordHash,
        role: 'CUSTOMER',
        assignedById: user.id,
      },
      select: {
        id: true,
        email: true,
        name: true,
        company: true,
        phone: true,
        isActive: true,
        createdAt: true,
        assignedBy: { select: { id: true, name: true } },
      },
    })

    return NextResponse.json({ customer }, { status: 201 })
  } catch (error) {
    console.error('Error al crear cliente:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ customers/route.ts corregido"

# ============================================================
# BUG 3: Lista de supervisors incluye inactivos
# ============================================================
echo "📝 [3/13] Corrigiendo supervisors/route.ts (filtrar inactivos)..."

cat > src/app/api/users/supervisors/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'
import { hashPassword } from '@/lib/auth'

export async function GET(request: NextRequest) {
  try {
    const authResult = await requireAuth(['MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const supervisors = await db.user.findMany({
      where: { role: 'SUPERVISOR', isActive: true },
      select: {
        id: true,
        email: true,
        name: true,
        phone: true,
        isActive: true,
        createdAt: true,
        _count: {
          select: {
            assignedReviews: true,
            supervisorResponses: true,
          },
        },
      },
      orderBy: { name: 'asc' },
    })

    return NextResponse.json({ supervisors })
  } catch (error) {
    console.error('Error al listar supervisores:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}

export async function POST(request: NextRequest) {
  try {
    const authResult = await requireAuth(['MANAGER', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const body = await request.json()
    const { email, name, phone, password } = body

    if (!email || !name || !password) {
      return NextResponse.json(
        { error: 'Email, nombre y contraseña son requeridos' },
        { status: 400 }
      )
    }

    if (password.length < 6) {
      return NextResponse.json(
        { error: 'La contraseña debe tener al menos 6 caracteres' },
        { status: 400 }
      )
    }

    const existingUser = await db.user.findUnique({
      where: { email: email.toLowerCase().trim() },
    })

    if (existingUser) {
      return NextResponse.json(
        { error: 'Ya existe una cuenta con este email' },
        { status: 409 }
      )
    }

    const passwordHash = await hashPassword(password)

    const supervisor = await db.user.create({
      data: {
        email: email.toLowerCase().trim(),
        name: name.trim(),
        phone: phone?.trim() || null,
        passwordHash,
        role: 'SUPERVISOR',
      },
      select: {
        id: true,
        email: true,
        name: true,
        phone: true,
        isActive: true,
        createdAt: true,
      },
    })

    return NextResponse.json({ supervisor }, { status: 201 })
  } catch (error) {
    console.error('Error al crear supervisor:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ supervisors/route.ts corregido"

# ============================================================
# BUG 4: Subida de fotos rota (key mismatch photos/photo)
# ============================================================
echo "📝 [4/13] Corrigiendo reviews/[id]/photos/route.ts (subida de fotos)..."

cat > src/app/api/reviews/\[id\]/photos/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'
import { writeFile, mkdir } from 'fs/promises'
import path from 'path'

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth(['CUSTOMER'])(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult
    const { id: reviewId } = await params

    // Verify review exists and belongs to this customer
    const review = await db.review.findFirst({ where: { id: reviewId, deletedAt: null } })
    if (!review) {
      return NextResponse.json(
        { error: 'Reseña no encontrada' },
        { status: 404 }
      )
    }
    if (review.customerId !== user.id) {
      return NextResponse.json(
        { error: 'Acceso denegado' },
        { status: 403 }
      )
    }

    // Check max 3 photos per review
    const photoCount = await db.reviewPhoto.count({ where: { reviewId } })
    if (photoCount >= 3) {
      return NextResponse.json(
        { error: 'Máximo 3 fotos por reseña' },
        { status: 400 }
      )
    }

    const formData = await request.formData()
    // Client sends files under 'photos' key (matching api.ts uploadPhotos)
    const fileEntries = formData.getAll('photos')
    const files = fileEntries.filter((f): f is File => f instanceof File)

    // Fallback: also support 'photo' (singular) for backward compatibility
    if (files.length === 0) {
      const singleFile = formData.get('photo')
      if (singleFile && singleFile instanceof File) {
        files.push(singleFile)
      }
    }

    if (files.length === 0) {
      return NextResponse.json(
        { error: 'No se proporcionó archivo' },
        { status: 400 }
      )
    }

    const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
    const uploadedPhotos = []

    for (const file of files) {
      // Check remaining photo slots
      const currentCount = await db.reviewPhoto.count({ where: { reviewId } })
      if (currentCount >= 3) break

      // Check file size (5MB max)
      if (file.size > 5 * 1024 * 1024) continue

      // Check file type
      if (!allowedTypes.includes(file.type)) continue

      // Generate unique filename
      const ext = file.name.split('.').pop() || 'jpg'
      const filename = `${Date.now()}-${Math.random().toString(36).substring(2, 8)}.${ext}`
      const uploadDir = path.join(process.cwd(), 'public', 'uploads', 'reviews', reviewId)
      const filePath = path.join(uploadDir, filename)

      // Create directory if it doesn't exist
      await mkdir(uploadDir, { recursive: true })

      // Write file
      const bytes = await file.arrayBuffer()
      const buffer = Buffer.from(bytes)
      await writeFile(filePath, buffer)

      const storageKey = `/uploads/reviews/${reviewId}/${filename}`

      // Save photo record in database
      const photo = await db.reviewPhoto.create({
        data: {
          reviewId,
          storageKey,
          fileName: file.name,
          sizeBytes: file.size,
        },
      })

      uploadedPhotos.push(photo)
    }

    return NextResponse.json({ photos: uploadedPhotos }, { status: 201 })
  } catch (error) {
    console.error('Error al subir foto:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth()(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult
    const { id: reviewId } = await params

    const review = await db.review.findFirst({ where: { id: reviewId, deletedAt: null } })
    if (!review) {
      return NextResponse.json(
        { error: 'Reseña no encontrada' },
        { status: 404 }
      )
    }

    // CUSTOMER solo puede ver fotos de sus propias reseñas
    if (user.role === 'CUSTOMER' && review.customerId !== user.id) {
      return NextResponse.json({ error: 'Acceso denegado' }, { status: 403 })
    }

    const photos = await db.reviewPhoto.findMany({
      where: { reviewId },
      orderBy: { uploadedAt: 'asc' },
    })

    return NextResponse.json({ photos })
  } catch (error) {
    console.error('Error al obtener fotos:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ reviews/[id]/photos/route.ts corregido"

# ============================================================
# BUG 5: Supervisor puede responder reseñas de otros
# ============================================================
echo "📝 [5/13] Corrigiendo reviews/[id]/respond/route.ts (verificar asignación)..."

cat > src/app/api/reviews/\[id\]/respond/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'
import { notifyUsers } from '@/lib/notifications'

export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth(['SUPERVISOR', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult
    const { id } = await params
    const body = await request.json()
    const { actionTaken, internalNote, responseToClient } = body

    if (!actionTaken || !responseToClient) {
      return NextResponse.json(
        { error: 'Acciones tomadas y respuesta al cliente son requeridas' },
        { status: 400 }
      )
    }

    const review = await db.review.findFirst({
      where: { id, deletedAt: null },
      include: { customer: { select: { id: true, name: true } } },
    })

    if (!review) {
      return NextResponse.json(
        { error: 'Reseña no encontrada' },
        { status: 404 }
      )
    }

    // Verify supervisor is assigned to this review (ADMIN can respond to any)
    if (user.role === 'SUPERVISOR' && review.assignedToId !== user.id) {
      return NextResponse.json(
        { error: 'Esta reseña no está asignada a usted' },
        { status: 403 }
      )
    }

    // Create the supervisor response (allow multiple responses for follow-ups)
    const response = await db.supervisorResponse.create({
      data: {
        reviewId: id,
        supervisorId: user.id,
        actionTaken: actionTaken.trim(),
        internalNote: internalNote?.trim() || '',
        responseToClient: responseToClient.trim(),
      },
    })

    await db.review.update({
      where: { id },
      data: {
        status: 'RESOLVED',
        resolvedAt: new Date(),
        notifiedAt: review.notifiedAt || new Date(),
      },
    })

    // Notify the customer about the response
    await notifyUsers({
      userIds: [review.customerId],
      title: 'Respuesta a su reseña',
      message: `Su reseña ${review.reviewCode} ha recibido una respuesta. ${responseToClient}`,
      type: 'RESPONSE_TO_CLIENT',
      reviewId: review.id,
    })

    return NextResponse.json({ response })
  } catch (error) {
    console.error('Error al responder reseña:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ reviews/[id]/respond/route.ts corregido"

# ============================================================
# BUG 6: Supervisor puede acusear reseñas de otros
# ============================================================
echo "📝 [6/13] Corrigiendo reviews/[id]/acknowledge/route.ts (verificar asignación)..."

cat > src/app/api/reviews/\[id\]/acknowledge/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'

export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const authResult = await requireAuth(['SUPERVISOR', 'ADMIN'])(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult
    const { id } = await params

    const review = await db.review.findFirst({ where: { id, deletedAt: null } })

    if (!review) {
      return NextResponse.json(
        { error: 'Reseña no encontrada' },
        { status: 404 }
      )
    }

    // Verify supervisor is assigned to this review (ADMIN can acknowledge any)
    if (user.role === 'SUPERVISOR' && review.assignedToId !== user.id) {
      return NextResponse.json(
        { error: 'Esta reseña no está asignada a usted' },
        { status: 403 }
      )
    }

    if (review.status !== 'PENDING') {
      return NextResponse.json(
        { error: 'Solo se pueden acusear reseñas pendientes' },
        { status: 400 }
      )
    }

    const updated = await db.review.update({
      where: { id },
      data: { status: 'ACKNOWLEDGED' },
      include: {
        customer: { select: { id: true, name: true, email: true } },
        assignedTo: { select: { id: true, name: true } },
      },
    })

    return NextResponse.json({ review: updated })
  } catch (error) {
    console.error('Error al acusear reseña:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ reviews/[id]/acknowledge/route.ts corregido"

# ============================================================
# BUG 7: Contador notificaciones retorna key incorrecta
# ============================================================
echo "📝 [7/13] Corrigiendo notifications/unread-count/route.ts (count key)..."

cat > src/app/api/notifications/unread-count/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'

export async function GET(request: NextRequest) {
  try {
    const authResult = await requireAuth()(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult

    const unreadCount = await db.notification.count({
      where: { userId: user.id, isRead: false },
    })

    return NextResponse.json({ count: unreadCount })
  } catch (error) {
    console.error('Error al contar notificaciones:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ notifications/unread-count/route.ts corregido"

# ============================================================
# BUG 8: Ruta de archivos sin autenticación
# ============================================================
echo "📝 [8/13] Corrigiendo files/[...path]/route.ts (agregar auth)..."

cat > src/app/api/files/\[...path\]/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { readFile, stat } from 'fs/promises'
import { join } from 'path'
import { existsSync } from 'fs'
import { requireAuth } from '@/lib/api-auth'

const PUBLIC_DIR = join(process.cwd(), 'public')

const MIME_TYPES: Record<string, string> = {
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.png': 'image/png',
  '.gif': 'image/gif',
  '.webp': 'image/webp',
  '.svg': 'image/svg+xml',
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ path: string[] }> }
) {
  try {
    // Require authentication to access uploaded files
    const authResult = await requireAuth()(request)
    if ('error' in authResult) return authResult.error

    const { path: pathSegments } = await params

    // Security: prevent directory traversal
    const safePath = pathSegments
      .map(segment => segment.replace(/\.\./g, '').replace(/\\/g, ''))
      .filter(Boolean)
      .join('/')

    if (!safePath) {
      return NextResponse.json({ error: 'Ruta inválida' }, { status: 400 })
    }

    const filePath = join(PUBLIC_DIR, safePath)

    // Security: ensure the resolved path is still within PUBLIC_DIR
    if (!filePath.startsWith(PUBLIC_DIR)) {
      return NextResponse.json({ error: 'Acceso denegado' }, { status: 403 })
    }

    if (!existsSync(filePath)) {
      return NextResponse.json({ error: 'Archivo no encontrado' }, { status: 404 })
    }

    const fileStat = await stat(filePath)

    // Don't serve directories
    if (!fileStat.isFile()) {
      return NextResponse.json({ error: 'No es un archivo' }, { status: 400 })
    }

    const fileBuffer = await readFile(filePath)

    // Determine content type from extension
    const ext = safePath.toLowerCase().match(/\.[^.]+$/)?.[0] || ''
    const contentType = MIME_TYPES[ext] || 'application/octet-stream'

    return new NextResponse(fileBuffer, {
      status: 200,
      headers: {
        'Content-Type': contentType,
        'Content-Length': fileStat.size.toString(),
        'Cache-Control': 'public, max-age=31536000, immutable',
      },
    })
  } catch (error) {
    console.error('Error al servir archivo:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ files/[...path]/route.ts corregido"

# ============================================================
# BUG 9: Usuarios inactivos pueden usar auth/me y change-password
# ============================================================
echo "📝 [9/13] Corrigiendo auth/me/route.ts (verificar isActive)..."

cat > src/app/api/auth/me/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'

export async function GET(request: NextRequest) {
  try {
    const authResult = await requireAuth()(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult

    const dbUser = await db.user.findUnique({
      where: { id: user.id },
      select: {
        id: true,
        email: true,
        name: true,
        company: true,
        phone: true,
        role: true,
        isActive: true,
        createdAt: true,
      },
    })

    if (!dbUser) {
      return NextResponse.json(
        { error: 'Usuario no encontrado' },
        { status: 404 }
      )
    }

    if (!dbUser.isActive) {
      return NextResponse.json(
        { error: 'Cuenta desactivada. Contacte al administrador.' },
        { status: 403 }
      )
    }

    return NextResponse.json({ user: dbUser })
  } catch (error) {
    console.error('Error al obtener perfil:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ auth/me/route.ts corregido"

echo "📝 [10/13] Corrigiendo auth/change-password/route.ts (verificar isActive)..."

cat > src/app/api/auth/change-password/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { requireAuth } from '@/lib/api-auth'
import { verifyPassword, hashPassword } from '@/lib/auth'

export async function POST(request: NextRequest) {
  try {
    const authResult = await requireAuth()(request)
    if ('error' in authResult) return authResult.error

    const { user } = authResult
    const body = await request.json()
    const { currentPassword, newPassword } = body

    if (!currentPassword || !newPassword) {
      return NextResponse.json(
        { error: 'Contraseña actual y nueva contraseña son requeridas' },
        { status: 400 }
      )
    }

    if (newPassword.length < 6) {
      return NextResponse.json(
        { error: 'La nueva contraseña debe tener al menos 6 caracteres' },
        { status: 400 }
      )
    }

    const dbUser = await db.user.findUnique({ where: { id: user.id } })
    if (!dbUser) {
      return NextResponse.json(
        { error: 'Usuario no encontrado' },
        { status: 404 }
      )
    }

    if (!dbUser.isActive) {
      return NextResponse.json(
        { error: 'Cuenta desactivada. Contacte al administrador.' },
        { status: 403 }
      )
    }

    const passwordValid = await verifyPassword(currentPassword, dbUser.passwordHash)
    if (!passwordValid) {
      return NextResponse.json(
        { error: 'Contraseña actual incorrecta' },
        { status: 400 }
      )
    }

    const newPasswordHash = await hashPassword(newPassword)
    await db.user.update({
      where: { id: user.id },
      data: { passwordHash: newPasswordHash },
    })

    return NextResponse.json({ message: 'Contraseña actualizada exitosamente' })
  } catch (error) {
    console.error('Error al cambiar contraseña:', error)
    return NextResponse.json(
      { error: 'Error interno del servidor' },
      { status: 500 }
    )
  }
}
ENDOFFILE

echo "   ✅ auth/change-password/route.ts corregido"

# ============================================================
# BUG 10: Cron de escalamiento duplica notificaciones
# ============================================================
echo "📝 [11/13] Corrigiendo cron/escalate/route.ts (evitar duplicados)..."

cat > src/app/api/cron/escalate/route.ts << 'ENDOFFILE'
import { NextRequest, NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { notifyUsers } from '@/lib/notifications'

export async function GET(request: NextRequest) {
  // Validar que la llamada viene del proceso autorizado
  const authHeader = request.headers.get('authorization')
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return NextResponse.json({ error: 'No autorizado' }, { status: 401 })
  }

  try {
    const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)

    // Buscar reseñas negativas PENDING sin respuesta por más de 24 horas
    // que NO hayan sido ya escaladas (no tienen notificación de tipo ESCALATION)
    const overdueReviews = await db.review.findMany({
      where: {
        status: 'PENDING',
        sentiment: 'NEGATIVE',
        deletedAt: null,
        createdAt: { lte: twentyFourHoursAgo },
      },
      include: {
        customer: { select: { id: true, name: true } },
        assignedTo: { select: { id: true, name: true } },
        notifications: {
          where: { type: 'ESCALATION' },
          select: { id: true },
          take: 1,
        },
      },
    })

    // Filter out reviews that have already been escalated
    const unescalatedReviews = overdueReviews.filter(
      (review) => review.notifications.length === 0
    )

    if (unescalatedReviews.length === 0) {
      return NextResponse.json({ escalated: 0 })
    }

    // Obtener todos los managers activos
    const managers = await db.user.findMany({
      where: { role: 'MANAGER', isActive: true },
      select: { id: true },
    })

    let escalatedCount = 0

    for (const review of unescalatedReviews) {
      // Notificar a todos los managers
      if (managers.length > 0) {
        await notifyUsers({
          userIds: managers.map(m => m.id),
          title: '🔴 Reseña sin atender — Escalamiento',
          message: `La reseña ${review.reviewCode} del cliente ${review.customer.name} lleva más de 24 horas sin respuesta del supervisor${review.assignedTo ? ` (asignado: ${review.assignedTo.name})` : ''}.`,
          type: 'ESCALATION',
          reviewId: review.id,
        })
      }

      escalatedCount++
    }

    return NextResponse.json({
      escalated: escalatedCount,
      reviewCodes: unescalatedReviews.map(r => r.reviewCode),
    })
  } catch (error) {
    console.error('Error en cron de escalamiento:', error)
    return NextResponse.json({ error: 'Error interno del servidor' }, { status: 500 })
  }
}
ENDOFFILE

echo "   ✅ cron/escalate/route.ts corregido"

# ============================================================
# BUG 11: Race condition en código de reseña
# ============================================================
echo "📝 [12/13] Corrigiendo lib/review-code.ts (race condition)..."

cat > src/lib/review-code.ts << 'ENDOFFILE'
import { db } from './db'
import { Prisma } from '@prisma/client'

export async function generateReviewCode(): Promise<string> {
  const year = new Date().getFullYear()
  const prefix = `REV-${year}-`

  // Use a transaction to safely get the next sequence number
  // This finds the MAX existing code with the same prefix and increments
  const result = await db.$transaction(async (tx) => {
    // Find the highest existing review code for this year
    const lastReview = await tx.review.findFirst({
      where: {
        reviewCode: { startsWith: prefix },
      },
      orderBy: { reviewCode: 'desc' },
      select: { reviewCode: true },
    })

    let nextSeq: number
    if (lastReview && lastReview.reviewCode) {
      // Extract the sequence number from the last code
      const parts = lastReview.reviewCode.split('-')
      const lastSeq = parseInt(parts[parts.length - 1], 10)
      nextSeq = lastSeq + 1
    } else {
      nextSeq = 1
    }

    const seq = nextSeq.toString().padStart(5, '0')
    const code = `${prefix}${seq}`

    return code
  })

  return result
}
ENDOFFILE

echo "   ✅ lib/review-code.ts corregido"

# ============================================================
# BUG 12: Estado compartido allReviews entre Manager y Admin
# + imports no usados + customerSearch no usado
# ============================================================
echo "📝 [13/13] Corrigiendo page.tsx (estado adminReviews + cleanup)..."

# Fix imports - remove unused Camera, Filter, TrendingDown, Image, Paperclip
sed -i 's/Eye, Send, Camera, Upload, Search, Filter, Download,/Eye, Send, Upload, Search, Download,/' src/app/page.tsx
sed -i 's/Settings, Shield, TrendingUp, TrendingDown, Activity,/Settings, Shield, TrendingUp, Activity,/' src/app/page.tsx
sed -i 's/Mail, Calendar, Tag, Image, Paperclip, Edit/Mail, Calendar, Tag, Edit/' src/app/page.tsx

# Remove unused token from destructuring
sed -i 's/const { user, token, isAuthenticated, login, logout, updateUser } = useAuthStore()/const { user, isAuthenticated, login, logout, updateUser } = useAuthStore()/' src/app/page.tsx

# Remove unused customerSearch state
sed -i '/const \[customerSearch, setCustomerSearch\] = useState/d' src/app/page.tsx

# Add adminReviews state after adminReviewsTotal
sed -i 's/const \[adminReviewsTotal, setAdminReviewsTotal\] = useState(0)/const [adminReviewsTotal, setAdminReviewsTotal] = useState(0)\n  const [adminReviews, setAdminReviews] = useState<Review[]>([])/' src/app/page.tsx

# Fix fetchAdminReviews to use setAdminReviews instead of setAllReviews
sed -i 's/setAllReviews(data\.reviews || \[\])/setAdminReviews(data.reviews || [])/' src/app/page.tsx

# Fix AdminReviews component to use adminReviews instead of allReviews
# This targets the specific line in the admin table body
sed -i 's/{allReviews\.map((r) => (/{adminReviews.map((r) => (/' src/app/page.tsx

echo "   ✅ page.tsx corregido (6 ediciones aplicadas)"

# ============================================================
# RESUMEN
# ============================================================
echo ""
echo "============================================"
echo "✅ TODAS LAS CORRECCIONES APLICADAS"
echo "============================================"
echo ""
echo "Resumen de bugs corregidos:"
echo "  1. findUnique → findFirst (error 500 en clientes)"
echo "  2. Lista de clientes filtra inactivos"
echo "  3. Lista de supervisores filtra inactivos"
echo "  4. Subida de fotos corregida (photos/photo)"
echo "  5. Supervisor solo responde sus reseñas asignadas"
echo "  6. Supervisor solo acusea sus reseñas asignadas"
echo "  7. Contador notificaciones retorna key correcta"
echo "  8. Ruta de archivos requiere autenticación"
echo "  9. Usuarios inactivos no pueden usar auth/me"
echo " 10. Usuarios inactivos no pueden cambiar contraseña"
echo " 11. Cron escalamiento no duplica notificaciones"
echo " 12. Código de reseña usa transacción (sin race condition)"
echo " 13. page.tsx: estado adminReviews separado + cleanup"
echo ""
echo "Pasos siguientes:"
echo "  1. bun run db:push"
echo "  2. npx tsx prisma/seed-admin.ts"
echo "  3. bun dev start"
echo ""
