package models

import (
	"encoding/json"
	"time"

	"github.com/sujit-baniya/fiber-boilerplate/app"
	"gorm.io/gorm"
)

// ─── Proyecto ─────────────────────────────────────────────────────────────────

type Proyecto struct {
	gorm.Model
	ClienteID   uint    `json:"cliente_id"   gorm:"column:cliente_id;index;not null"`
	Cliente     Cliente `json:"cliente"      gorm:"foreignKey:ClienteID"`
	Nombre      string  `json:"nombre"       gorm:"column:nombre;not null"`
	Slug        string  `json:"slug"         gorm:"column:slug;uniqueIndex;not null"`
	Descripcion string  `json:"descripcion"  gorm:"column:descripcion;type:text"`
	Color       string  `json:"color"        gorm:"column:color;default:'#8eb02f'"`
	Estado      string  `json:"estado"       gorm:"column:estado;default:'activo'"` // activo|pausado|completado
	Progreso    int     `json:"progreso"     gorm:"column:progreso;default:0"`      // 0-100
}

func (Proyecto) TableName() string { return "proyectos" }

// ─── ProyectoFase (roadmap steps) ─────────────────────────────────────────────

type ProyectoFase struct {
	gorm.Model
	ProyectoID      uint       `json:"proyecto_id"      gorm:"column:proyecto_id;index"`
	Nombre          string     `json:"nombre"           gorm:"column:nombre"`
	Descripcion     string     `json:"descripcion"      gorm:"column:descripcion;type:text"`
	Estado          string     `json:"estado"           gorm:"column:estado;default:'pendiente'"` // pendiente|en_progreso|completado
	Orden           int        `json:"orden"            gorm:"column:orden;default:0"`
	FechaEstimada   *time.Time `json:"fecha_estimada"   gorm:"column:fecha_estimada"`
	FechaCompletado *time.Time `json:"fecha_completado" gorm:"column:fecha_completado"`
	EntregablesJSON string     `json:"entregables_json" gorm:"column:entregables_json;type:text"`
	Entregables     []string   `json:"entregables"      gorm:"-"`
}

func (ProyectoFase) TableName() string { return "proyecto_fases" }

func (f *ProyectoFase) ParseEntregables() {
	if f.EntregablesJSON != "" {
		_ = json.Unmarshal([]byte(f.EntregablesJSON), &f.Entregables)
	}
	if f.Entregables == nil {
		f.Entregables = []string{}
	}
}

func (f *ProyectoFase) SerializeEntregables() {
	b, _ := json.Marshal(f.Entregables)
	f.EntregablesJSON = string(b)
}

// ─── ProyectoAvance (news feed / updates) ─────────────────────────────────────

type ProyectoAvance struct {
	gorm.Model
	ProyectoID uint   `json:"proyecto_id" gorm:"column:proyecto_id;index"`
	Titulo     string `json:"titulo"      gorm:"column:titulo"`
	Contenido  string `json:"contenido"   gorm:"column:contenido;type:text"`
	Tipo       string `json:"tipo"        gorm:"column:tipo;default:'update'"` // update|milestone|release
	Visible    bool   `json:"visible"     gorm:"column:visible;default:true"`
}

func (ProyectoAvance) TableName() string { return "proyecto_avances" }

// ─── ProyectoEntregable (downloadable files) ──────────────────────────────────

type ProyectoEntregable struct {
	gorm.Model
	ProyectoID   uint   `json:"proyecto_id"   gorm:"column:proyecto_id;index"`
	Nombre       string `json:"nombre"        gorm:"column:nombre"`
	Descripcion  string `json:"descripcion"   gorm:"column:descripcion;type:text"`
	Archivo      string `json:"archivo"       gorm:"column:archivo"`
	OriginalName string `json:"original_name" gorm:"column:original_name"`
	Version      string `json:"version"       gorm:"column:version"`
	TipoMime     string `json:"tipo_mime"     gorm:"column:tipo_mime"`
	Tamanio      int64  `json:"tamanio"       gorm:"column:tamanio"`
	Visible      bool   `json:"visible"       gorm:"column:visible;default:true"`
}

func (ProyectoEntregable) TableName() string { return "proyecto_entregables" }

// ─── Fase template (los 11 pasos de u-site) ───────────────────────────────────

var FaseTemplateDefault = []struct {
	Nombre      string
	Descripcion string
	Entregables []string
}{
	{"Captación y calificación", "Marketing de contenidos, ads y referidos. Primer contacto y diagnóstico rápido. Identificación del tipo de cliente y evaluación de presupuesto.", []string{"Lead calificado", "Brief inicial del problema"}},
	{"Descubrimiento y diagnóstico", "Reunión profunda sobre procesos y herramientas. Mapeo del flujo de trabajo actual. Identificación de cuellos de botella y priorización.", []string{"Documento de diagnóstico", "Lista de oportunidades"}},
	{"Definición de solución y alcance", "Diseño de arquitectura modular. Definición de módulos, componentes e integraciones. Priorización por fases (MVP → evolución).", []string{"Propuesta técnica", "Alcance funcional", "Roadmap del proyecto"}},
	{"Propuesta comercial y cierre", "Definición de modelo de cobro, presentación y ajustes según feedback. Negociación y firma.", []string{"Cotización formal", "Contrato / acuerdo", "Cronograma inicial"}},
	{"Diseño funcional y técnico", "Wireframes o prototipos, definición de APIs e integraciones, diseño de base de datos.", []string{"Especificación funcional", "Arquitectura definida", "Backlog de desarrollo"}},
	{"Desarrollo e implementación", "Desarrollo por módulos o iteraciones. Integraciones con herramientas externas. Reuniones de seguimiento.", []string{"Módulos funcionales", "Versiones iterativas"}},
	{"Pruebas y validación", "Pruebas técnicas y con usuario (UAT). Ajustes, correcciones y validación de flujos completos.", []string{"Sistema validado", "Lista de ajustes finales"}},
	{"Despliegue y puesta en producción", "Configuración de infraestructura, migración de datos, activación de automatizaciones y monitoreo inicial.", []string{"Sistema en producción", "Documentación básica de uso"}},
	{"Capacitación y adopción", "Entrenamiento al equipo, guías rápidas o videos, resolución de dudas y ajustes por uso real.", []string{"Usuarios activos", "Procesos adoptados"}},
	{"Soporte y mejora continua", "Soporte técnico, nuevas automatizaciones o módulos, optimización y evolución del sistema.", []string{"Roadmap evolutivo", "Mejoras continuas"}},
	{"Cierre formal del proyecto", "Validación final, entrega de documentación, evaluación de resultados (antes vs después) y testimonio.", []string{"Acta de cierre", "Caso de estudio (opcional)", "Oportunidades de upsell"}},
}

// ─── CRUD Proyecto ─────────────────────────────────────────────────────────────

func GetAllProyectos(limit, offset int, search string) ([]Proyecto, int64, error) {
	var items []Proyecto
	var total int64
	db := app.Http.Database.DB.Model(&Proyecto{}).Preload("Cliente")
	if search != "" {
		db = db.Where("proyectos.nombre ILIKE ? OR proyectos.descripcion ILIKE ?", "%"+search+"%", "%"+search+"%")
	}
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	if err := db.Order("proyectos.created_at DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
		return nil, 0, err
	}
	return items, total, nil
}

func GetProyectosByClienteIDs(clienteIDs []uint) ([]Proyecto, error) {
	if len(clienteIDs) == 0 {
		return []Proyecto{}, nil
	}
	var items []Proyecto
	err := app.Http.Database.DB.Preload("Cliente").Where("cliente_id IN ?", clienteIDs).Order("created_at DESC").Find(&items).Error
	return items, err
}

func GetProyectoByID(id uint) (*Proyecto, error) {
	var item Proyecto
	err := app.Http.Database.DB.Preload("Cliente").First(&item, id).Error
	return &item, err
}

func GetProyectoBySlug(slug string) (*Proyecto, error) {
	var item Proyecto
	err := app.Http.Database.DB.Preload("Cliente").Where("slug = ?", slug).First(&item).Error
	return &item, err
}

func CreateProyecto(p *Proyecto) error {
	return app.Http.Database.DB.Create(p).Error
}

func CalcularProgresoDesdeFases(proyectoID uint) int {
	var total, completados int64
	app.Http.Database.DB.Model(&ProyectoFase{}).Where("proyecto_id = ?", proyectoID).Count(&total)
	if total == 0 {
		return 0
	}
	app.Http.Database.DB.Model(&ProyectoFase{}).Where("proyecto_id = ? AND estado = ?", proyectoID, "completado").Count(&completados)
	return int((completados * 100) / total)
}

func ActualizarProgresoProyecto(proyectoID uint) error {
	nuevo := CalcularProgresoDesdeFases(proyectoID)
	return app.Http.Database.DB.Model(&Proyecto{}).Where("id = ?", proyectoID).Update("progreso", nuevo).Error
}

func UpdateProyecto(p *Proyecto) error {
	return app.Http.Database.DB.Model(&Proyecto{}).Where("id = ?", p.ID).Updates(map[string]interface{}{
		"nombre":      p.Nombre,
		"slug":        p.Slug,
		"descripcion": p.Descripcion,
		"color":       p.Color,
		"estado":      p.Estado,
		"progreso":    p.Progreso,
		"cliente_id":  p.ClienteID,
	}).Error
}

func DeleteProyecto(id uint) error {
	return app.Http.Database.DB.Delete(&Proyecto{}, id).Error
}

// ─── CRUD ProyectoFase ─────────────────────────────────────────────────────────

func GetFasesByProyecto(proyectoID uint) ([]ProyectoFase, error) {
	var items []ProyectoFase
	err := app.Http.Database.DB.Where("proyecto_id = ?", proyectoID).Order("orden ASC, id ASC").Find(&items).Error
	for i := range items {
		items[i].ParseEntregables()
	}
	return items, err
}

func CreateProyectoFase(f *ProyectoFase) error {
	f.SerializeEntregables()
	return app.Http.Database.DB.Create(f).Error
}

func UpdateProyectoFase(f *ProyectoFase) error {
	f.SerializeEntregables()
	return app.Http.Database.DB.Model(&ProyectoFase{}).Where("id = ?", f.ID).Updates(map[string]interface{}{
		"nombre":           f.Nombre,
		"descripcion":      f.Descripcion,
		"estado":           f.Estado,
		"orden":            f.Orden,
		"fecha_estimada":   f.FechaEstimada,
		"fecha_completado": f.FechaCompletado,
		"entregables_json": f.EntregablesJSON,
	}).Error
}

func DeleteProyectoFase(id uint) error {
	return app.Http.Database.DB.Delete(&ProyectoFase{}, id).Error
}

func ApplyFaseTemplate(proyectoID uint) error {
	if err := app.Http.Database.DB.Where("proyecto_id = ?", proyectoID).Delete(&ProyectoFase{}).Error; err != nil {
		return err
	}
	for i, tpl := range FaseTemplateDefault {
		ents, _ := json.Marshal(tpl.Entregables)
		fase := &ProyectoFase{
			ProyectoID:      proyectoID,
			Nombre:          tpl.Nombre,
			Descripcion:     tpl.Descripcion,
			Orden:           i + 1,
			Estado:          "pendiente",
			EntregablesJSON: string(ents),
		}
		if err := app.Http.Database.DB.Create(fase).Error; err != nil {
			return err
		}
	}
	return nil
}

// ─── CRUD ProyectoAvance ───────────────────────────────────────────────────────

func GetAvancesByProyecto(proyectoID uint, soloVisibles bool) ([]ProyectoAvance, error) {
	var items []ProyectoAvance
	db := app.Http.Database.DB.Where("proyecto_id = ?", proyectoID)
	if soloVisibles {
		db = db.Where("visible = true")
	}
	err := db.Order("created_at DESC").Find(&items).Error
	return items, err
}

func CreateProyectoAvance(a *ProyectoAvance) error {
	return app.Http.Database.DB.Create(a).Error
}

func UpdateProyectoAvance(a *ProyectoAvance) error {
	return app.Http.Database.DB.Model(&ProyectoAvance{}).Where("id = ?", a.ID).Updates(map[string]interface{}{
		"titulo":    a.Titulo,
		"contenido": a.Contenido,
		"tipo":      a.Tipo,
		"visible":   a.Visible,
	}).Error
}

func DeleteProyectoAvance(id uint) error {
	return app.Http.Database.DB.Delete(&ProyectoAvance{}, id).Error
}

// ─── CRUD ProyectoEntregable ───────────────────────────────────────────────────

func GetEntregablesByProyecto(proyectoID uint, soloVisibles bool) ([]ProyectoEntregable, error) {
	var items []ProyectoEntregable
	db := app.Http.Database.DB.Where("proyecto_id = ?", proyectoID)
	if soloVisibles {
		db = db.Where("visible = true")
	}
	err := db.Order("created_at DESC").Find(&items).Error
	return items, err
}

func CreateProyectoEntregable(e *ProyectoEntregable) error {
	return app.Http.Database.DB.Create(e).Error
}

func GetProyectoEntregableByID(id uint) (*ProyectoEntregable, error) {
	var item ProyectoEntregable
	err := app.Http.Database.DB.First(&item, id).Error
	return &item, err
}

func DeleteProyectoEntregable(id uint) error {
	return app.Http.Database.DB.Delete(&ProyectoEntregable{}, id).Error
}

func UpdateEntregableVisibilidad(id uint, visible bool) error {
	return app.Http.Database.DB.Model(&ProyectoEntregable{}).Where("id = ?", id).Update("visible", visible).Error
}

// ─── ProyectoDocumento (contratos y órdenes de servicio) ──────────────────────

type ProyectoDocumento struct {
	gorm.Model
	ProyectoID   uint   `json:"proyecto_id"   gorm:"column:proyecto_id;index"`
	Tipo         string `json:"tipo"          gorm:"column:tipo;default:'contrato'"` // contrato|orden_servicio|otro
	Nombre       string `json:"nombre"        gorm:"column:nombre"`
	Descripcion  string `json:"descripcion"   gorm:"column:descripcion;type:text"`
	Archivo      string `json:"archivo"       gorm:"column:archivo"`
	OriginalName string `json:"original_name" gorm:"column:original_name"`
	TipoMime     string `json:"tipo_mime"     gorm:"column:tipo_mime"`
	Tamanio      int64  `json:"tamanio"       gorm:"column:tamanio"`
}

func (ProyectoDocumento) TableName() string { return "proyecto_documentos" }

func GetDocumentosByProyecto(proyectoID uint) ([]ProyectoDocumento, error) {
	var items []ProyectoDocumento
	err := app.Http.Database.DB.Where("proyecto_id = ?", proyectoID).Order("created_at DESC").Find(&items).Error
	return items, err
}

func CreateProyectoDocumento(d *ProyectoDocumento) error {
	return app.Http.Database.DB.Create(d).Error
}

func GetProyectoDocumentoByID(id uint) (*ProyectoDocumento, error) {
	var item ProyectoDocumento
	err := app.Http.Database.DB.First(&item, id).Error
	return &item, err
}

func DeleteProyectoDocumento(id uint) error {
	return app.Http.Database.DB.Delete(&ProyectoDocumento{}, id).Error
}
