package services

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)

func slugifyProyecto(s string) string {
	s = strings.ToLower(s)
	replacer := strings.NewReplacer(
		" ", "-", "á", "a", "é", "e", "í", "i", "ó", "o", "ú", "u",
		"ñ", "n", "ü", "u",
	)
	s = replacer.Replace(s)
	var b strings.Builder
	for _, r := range s {
		if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' {
			b.WriteRune(r)
		}
	}
	return strings.Trim(b.String(), "-")
}

// CrearProyectoSimple crea un proyecto para un cliente a partir del flujo de
// automatización con IA ("nombre, stack, cliente asociado"). El stack se antepone
// a la descripción; la creación de repo/estructura inicial queda fuera de este
// alcance (requiere integración con un proveedor Git, no cubierta aún).
func CrearProyectoSimple(clienteID uint, nombre, stack, descripcion string) (*models.Proyecto, error) {
	if clienteID == 0 {
		return nil, fmt.Errorf("cliente_id requerido")
	}
	if strings.TrimSpace(nombre) == "" {
		return nil, fmt.Errorf("nombre requerido")
	}
	if stack != "" {
		descripcion = fmt.Sprintf("Stack: %s\n\n%s", stack, descripcion)
	}
	p := &models.Proyecto{
		ClienteID:   clienteID,
		Nombre:      nombre,
		Slug:        slugifyProyecto(nombre),
		Descripcion: descripcion,
		Color:       "#8eb02f",
		Estado:      "activo",
	}
	if err := models.CreateProyecto(p); err != nil {
		return nil, fmt.Errorf("no se pudo crear el proyecto: %w", err)
	}
	return p, nil
}

// CrearFaseProyecto agrega una fase/etapa a un proyecto ya existente, para el
// flujo de automatización con IA ("registra el proyecto y coloca las fases").
func CrearFaseProyecto(proyectoID uint, nombre, descripcion, estado string, orden int, fechaEstimada *time.Time) (*models.ProyectoFase, error) {
	if proyectoID == 0 {
		return nil, fmt.Errorf("proyecto_id requerido")
	}
	if strings.TrimSpace(nombre) == "" {
		return nil, fmt.Errorf("nombre requerido")
	}
	if estado == "" {
		estado = "pendiente"
	}
	f := &models.ProyectoFase{
		ProyectoID:    proyectoID,
		Nombre:        nombre,
		Descripcion:   descripcion,
		Estado:        estado,
		Orden:         orden,
		FechaEstimada: fechaEstimada,
	}
	if err := models.CreateProyectoFase(f); err != nil {
		return nil, fmt.Errorf("no se pudo crear la fase: %w", err)
	}
	_ = models.ActualizarProgresoProyecto(proyectoID)
	return f, nil
}

// AdjuntarDocumentoProyecto toma el archivo pendiente de Telegram para este chat
// (descargado por el webhook) y lo guarda como documento del proyecto, igual que
// si se subiera desde el dashboard.
func AdjuntarDocumentoProyecto(chatID int64, proyectoID uint, tipo, nombre, descripcion string) (*models.ProyectoDocumento, error) {
	if proyectoID == 0 {
		return nil, fmt.Errorf("proyecto_id requerido")
	}
	att, ok := PopTelegramAttachment(chatID)
	if !ok {
		return nil, fmt.Errorf("no hay ningún documento pendiente en este chat; pide al usuario que lo envíe de nuevo")
	}
	if tipo == "" {
		tipo = "otro"
	}
	if nombre == "" {
		nombre = att.OriginalName
	}

	dir := fmt.Sprintf("uploads/proyectos/%d/docs", proyectoID)
	if err := os.MkdirAll(dir, 0755); err != nil {
		_ = os.Remove(att.Path)
		return nil, fmt.Errorf("no se pudo crear el directorio: %w", err)
	}
	ext := filepath.Ext(att.OriginalName)
	finalPath := filepath.Join(dir, fmt.Sprintf("telegram_%d%s", time.Now().UnixNano(), ext))
	if err := os.Rename(att.Path, finalPath); err != nil {
		return nil, fmt.Errorf("no se pudo guardar el archivo: %w", err)
	}

	var tamanio int64
	if info, err := os.Stat(finalPath); err == nil {
		tamanio = info.Size()
	}

	d := &models.ProyectoDocumento{
		ProyectoID:   proyectoID,
		Tipo:         tipo,
		Nombre:       nombre,
		Descripcion:  descripcion,
		Archivo:      finalPath,
		OriginalName: att.OriginalName,
		TipoMime:     att.MimeType,
		Tamanio:      tamanio,
	}
	if err := models.CreateProyectoDocumento(d); err != nil {
		return nil, err
	}
	return d, nil
}
