package controllers

import (
	"nearle/db"
	"nearle/models"
	"net/http"
	"strconv"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm/clause"
)

func GetSubstitutions(c *fiber.Ctx) error {
	tenantID, _ := strconv.Atoi(c.Query("tenant_id"))
	if tenantID == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Missing tenant_id",
			"status":  false,
		})
	}

	date := c.Query("date")
	fromDate := c.Query("from_date")
	toDate := c.Query("to_date")
	status := c.Query("status")

	query := db.DB.Model(&models.RiderSubstitution{}).Where("tenant_id = ?", tenantID)

	if date != "" {
		query = query.Where("sub_date = ?", date)
	}
	if fromDate != "" && toDate != "" {
		query = query.Where("sub_date >= ? AND sub_date <= ?", fromDate, toDate)
	}
	if status != "" {
		query = query.Where("status = ?", status)
	}

	var results []models.RiderSubstitution
	if err := query.Find(&results).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"count":   len(results),
		"details": results,
		"status":  true,
	})
}

func GetSubstitutionByID(c *fiber.Ctx) error {
	id := c.Params("id")
	tenantID, _ := strconv.Atoi(c.Query("tenant_id"))

	var result models.RiderSubstitution
	if err := db.DB.Where("id = ? AND tenant_id = ?", id, tenantID).First(&result).Error; err != nil {
		return c.Status(http.StatusNotFound).JSON(fiber.Map{
			"code":    http.StatusNotFound,
			"message": "Record not found",
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"details": result,
		"status":  true,
	})
}

type CreateSubstitutionsRequest struct {
	TenantID      int                        `json:"tenant_id"`
	Substitutions []models.RiderSubstitution `json:"substitutions"`
}

func CreateSubstitutions(c *fiber.Ctx) error {
	var req CreateSubstitutionsRequest
	if err := c.BodyParser(&req); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

	for i := range req.Substitutions {
		req.Substitutions[i].TenantID = req.TenantID
		if req.Substitutions[i].Status == "" {
			req.Substitutions[i].Status = "scheduled"
		}
	}

	if len(req.Substitutions) == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "No substitutions provided",
			"status":  false,
		})
	}

	// Upsert to handle unique constraint on (tenant_id, sub_date, absent_rider_id)
	if err := db.DB.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "tenant_id"}, {Name: "sub_date"}, {Name: "absent_rider_id"}},
		UpdateAll: true,
	}).Create(&req.Substitutions).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":       http.StatusOK,
		"registered": len(req.Substitutions),
		"details":    req.Substitutions,
		"status":     true,
	})
}

func UpdateSubstitution(c *fiber.Ctx) error {
	id := c.Params("id")
	var updateData map[string]interface{}

	if err := c.BodyParser(&updateData); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

	tenantIDStr := updateData["tenant_id"]
	if tenantIDStr == nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Missing tenant_id in body",
			"status":  false,
		})
	}

	var tenantID int
	switch v := tenantIDStr.(type) {
	case float64:
		tenantID = int(v)
	case string:
		tenantID, _ = strconv.Atoi(v)
	}

	if err := db.DB.Model(&models.RiderSubstitution{}).Where("id = ? AND tenant_id = ?", id, tenantID).Updates(updateData).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Updated successfully",
		"status":  true,
	})
}

func UpdateSubstitutionStatus(c *fiber.Ctx) error {
	id := c.Params("id")
	var req struct {
		TenantID int    `json:"tenant_id"`
		Status   string `json:"status"`
	}

	if err := c.BodyParser(&req); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

	if req.TenantID == 0 || req.Status == "" {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Missing tenant_id or status",
			"status":  false,
		})
	}

	if err := db.DB.Model(&models.RiderSubstitution{}).Where("id = ? AND tenant_id = ?", id, req.TenantID).Update("status", req.Status).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Status updated successfully",
		"status":  true,
	})
}

func DeleteSubstitution(c *fiber.Ctx) error {
	id := c.Params("id")
	tenantID, _ := strconv.Atoi(c.Query("tenant_id"))

	if tenantID == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Missing tenant_id",
			"status":  false,
		})
	}

	// Soft delete by updating status to 'cancelled'
	if err := db.DB.Model(&models.RiderSubstitution{}).Where("id = ? AND tenant_id = ?", id, tenantID).Update("status", "cancelled").Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Deleted successfully",
		"status":  true,
	})
}
