package services

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"time"

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

// CrearTareaAsignada crea una tarea, opcionalmente ya asignada a alguien, y
// dispara la notificación correspondiente (Telegram/email/sistema, según la
// config de notif_evento_configs) si quedó asignada a un usuario.
func CrearTareaAsignada(titulo, descripcion, estado, prioridad string, asignadoID *uint, fechaLimite *time.Time) (*models.Tarea, error) {
	if titulo == "" {
		return nil, fmt.Errorf("titulo requerido")
	}
	if estado == "" {
		// Debe coincidir con las columnas del Kanban (tareas.html): por_hacer,
		// en_progreso, revision, hecho. "pendiente" no es ninguna de esas — una
		// tarea con ese estado se guarda pero no aparece en ninguna columna.
		estado = "por_hacer"
	}
	if prioridad == "" {
		prioridad = "media"
	}
	t := &models.Tarea{
		Titulo:      titulo,
		Descripcion: descripcion,
		Estado:      estado,
		Prioridad:   prioridad,
		AsignadoID:  asignadoID,
		FechaLimite: fechaLimite,
	}
	if err := models.CreateTarea(t); err != nil {
		return nil, fmt.Errorf("no se pudo crear la tarea: %w", err)
	}
	if asignadoID != nil {
		if full, err := models.GetTareaByID(t.ID); err == nil {
			go NotificarTareaAsignada(full)
		}
	}
	return t, nil
}

// AsignarTarea cambia el responsable de una tarea existente y notifica al nuevo
// asignado si el responsable realmente cambió. asignadoID puede ser nil para
// dejar la tarea sin asignar.
func AsignarTarea(id uint, asignadoID *uint) (*models.Tarea, error) {
	if id == 0 {
		return nil, fmt.Errorf("id requerido")
	}
	tarea, err := models.GetTareaByID(id)
	if err != nil {
		return nil, fmt.Errorf("tarea no encontrada: %w", err)
	}
	prevAsignado := tarea.AsignadoID
	tarea.AsignadoID = asignadoID
	if err := models.SaveTarea(tarea); err != nil {
		return nil, fmt.Errorf("no se pudo asignar la tarea: %w", err)
	}
	full, _ := models.GetTareaByID(id)
	if cambioAsignado(prevAsignado, asignadoID) && full != nil {
		go NotificarTareaAsignada(full)
	}
	return full, nil
}

// AdjuntarDocumentoTarea guarda como comentario de una tarea el archivo (PDF/foto)
// que el usuario acaba de enviar por Telegram en este chat. Reutiliza el mismo
// formato de "archivos" (JSON) que ya usa el comentario web (AddComentario), para
// que el archivo aparezca igual en /app/tareas sin importar de dónde se subió.
func AdjuntarDocumentoTarea(chatID int64, tareaID uint, comentario string) (*models.TareaComentario, error) {
	if tareaID == 0 {
		return nil, fmt.Errorf("id de tarea requerido")
	}
	tarea, err := models.GetTareaByID(tareaID)
	if err != nil {
		return nil, fmt.Errorf("tarea no encontrada: %w", err)
	}
	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 comentario == "" {
		comentario = fmt.Sprintf("Archivo adjunto vía Telegram: %s", att.OriginalName)
	}

	dir := fmt.Sprintf("uploads/tareas/%d", tareaID)
	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("%d_telegram%s", time.Now().UnixMilli(), ext))
	if err := os.Rename(att.Path, finalPath); err != nil {
		return nil, fmt.Errorf("no se pudo guardar el archivo: %w", err)
	}

	archivosJSON, _ := json.Marshal([]map[string]string{
		{"nombre": att.OriginalName, "ruta": finalPath},
	})

	c := &models.TareaComentario{
		TareaID:   tareaID,
		Contenido: comentario,
		Archivos:  string(archivosJSON),
	}
	if err := models.CreateComentario(c); err != nil {
		return nil, fmt.Errorf("no se pudo guardar el comentario: %w", err)
	}
	go NotificarTareaComentario(tarea, comentario)
	return c, nil
}

func cambioAsignado(a, b *uint) bool {
	if a == nil && b == nil {
		return false
	}
	if a == nil || b == nil {
		return true
	}
	return *a != *b
}
