package handlers

import (
	"net/http"
	"strconv"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/admin/dto"
	"github.com/treytartt/honeydue-api/internal/models"
)

// AdminResidenceHandler handles admin residence management endpoints
type AdminResidenceHandler struct {
	db *gorm.DB
}

// NewAdminResidenceHandler creates a new admin residence handler
func NewAdminResidenceHandler(db *gorm.DB) *AdminResidenceHandler {
	return &AdminResidenceHandler{db: db}
}

// List handles GET /api/admin/residences
func (h *AdminResidenceHandler) List(c echo.Context) error {
	var filters dto.ResidenceFilters
	if err := c.Bind(&filters); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	var residences []models.Residence
	var total int64

	query := h.db.Model(&models.Residence{}).
		Preload("Owner").
		Preload("PropertyType").
		Preload("Users")

	// Apply search
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Where(
			"name ILIKE ? OR street_address ILIKE ? OR city ILIKE ?",
			search, search, search,
		)
	}

	// Apply filters
	if filters.IsActive != nil {
		query = query.Where("is_active = ?", *filters.IsActive)
	}
	if filters.OwnerID != nil {
		query = query.Where("owner_id = ?", *filters.OwnerID)
	}

	// Get total count
	query.Count(&total)

	// Apply sorting (allowlist prevents SQL injection via sort_by parameter)
	sortBy := filters.GetSafeSortBy([]string{
		"id", "name", "created_at", "updated_at", "owner_id",
		"city", "state_province", "country", "is_active", "is_primary",
	}, "created_at")
	query = query.Order(sortBy + " " + filters.GetSortDir())

	// Apply pagination
	query = query.Offset(filters.GetOffset()).Limit(filters.GetPerPage())

	if err := query.Find(&residences).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch residences"})
	}

	// Build response
	responses := make([]dto.ResidenceResponse, len(residences))
	for i, res := range residences {
		responses[i] = h.toResidenceResponse(&res)
	}

	return c.JSON(http.StatusOK, dto.NewPaginatedResponse(responses, total, filters.GetPage(), filters.GetPerPage()))
}

// Get handles GET /api/admin/residences/:id
func (h *AdminResidenceHandler) Get(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid residence ID"})
	}

	var residence models.Residence
	if err := h.db.Preload("Owner").Preload("PropertyType").Preload("Users").First(&residence, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Residence not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch residence"})
	}

	response := dto.ResidenceDetailResponse{
		ResidenceResponse: h.toResidenceResponse(&residence),
	}

	// Add owner info
	response.Owner = &dto.UserSummary{
		ID:       residence.Owner.ID,
		Username: residence.Owner.Username,
		Email:    residence.Owner.Email,
	}

	// Add shared users
	for _, user := range residence.Users {
		response.SharedUsers = append(response.SharedUsers, dto.UserSummary{
			ID:       user.ID,
			Username: user.Username,
			Email:    user.Email,
		})
	}

	// Get counts
	var taskCount, documentCount int64
	h.db.Model(&models.Task{}).Where("residence_id = ?", residence.ID).Count(&taskCount)
	h.db.Model(&models.Document{}).Where("residence_id = ?", residence.ID).Count(&documentCount)
	response.TaskCount = int(taskCount)
	response.DocumentCount = int(documentCount)

	return c.JSON(http.StatusOK, response)
}

// Update handles PUT /api/admin/residences/:id
func (h *AdminResidenceHandler) Update(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid residence ID"})
	}

	var residence models.Residence
	if err := h.db.First(&residence, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Residence not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch residence"})
	}

	var req dto.UpdateResidenceRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	if req.OwnerID != nil {
		// Verify owner exists
		var owner models.User
		if err := h.db.First(&owner, *req.OwnerID).Error; err != nil {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Owner not found"})
		}
		residence.OwnerID = *req.OwnerID
	}
	if req.Name != nil {
		residence.Name = *req.Name
	}
	if req.PropertyTypeID != nil {
		residence.PropertyTypeID = req.PropertyTypeID
	}
	if req.StreetAddress != nil {
		residence.StreetAddress = *req.StreetAddress
	}
	if req.ApartmentUnit != nil {
		residence.ApartmentUnit = *req.ApartmentUnit
	}
	if req.City != nil {
		residence.City = *req.City
	}
	if req.StateProvince != nil {
		residence.StateProvince = *req.StateProvince
	}
	if req.PostalCode != nil {
		residence.PostalCode = *req.PostalCode
	}
	if req.Country != nil {
		residence.Country = *req.Country
	}
	if req.Bedrooms != nil {
		residence.Bedrooms = req.Bedrooms
	}
	if req.Bathrooms != nil {
		d := decimal.NewFromFloat(*req.Bathrooms)
		residence.Bathrooms = &d
	}
	if req.SquareFootage != nil {
		residence.SquareFootage = req.SquareFootage
	}
	if req.LotSize != nil {
		d := decimal.NewFromFloat(*req.LotSize)
		residence.LotSize = &d
	}
	if req.YearBuilt != nil {
		residence.YearBuilt = req.YearBuilt
	}
	if req.Description != nil {
		residence.Description = *req.Description
	}
	if req.PurchaseDate != nil {
		if purchaseDate, err := time.Parse("2006-01-02", *req.PurchaseDate); err == nil {
			residence.PurchaseDate = &purchaseDate
		}
	}
	if req.PurchasePrice != nil {
		residence.PurchasePrice = req.PurchasePrice
	}
	if req.IsActive != nil {
		residence.IsActive = *req.IsActive
	}
	if req.IsPrimary != nil {
		residence.IsPrimary = *req.IsPrimary
	}

	if err := h.db.Save(&residence).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to update residence"})
	}

	h.db.Preload("Owner").Preload("PropertyType").First(&residence, id)
	return c.JSON(http.StatusOK, h.toResidenceResponse(&residence))
}

// Create handles POST /api/admin/residences
func (h *AdminResidenceHandler) Create(c echo.Context) error {
	var req dto.CreateResidenceRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	// Verify owner exists
	var owner models.User
	if err := h.db.First(&owner, req.OwnerID).Error; err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Owner not found"})
	}

	residence := models.Residence{
		OwnerID:        req.OwnerID,
		Name:           req.Name,
		PropertyTypeID: req.PropertyTypeID,
		StreetAddress:  req.StreetAddress,
		ApartmentUnit:  req.ApartmentUnit,
		City:           req.City,
		StateProvince:  req.StateProvince,
		PostalCode:     req.PostalCode,
		Country:        req.Country,
		Description:    req.Description,
		IsPrimary:      req.IsPrimary,
		IsActive:       true,
	}

	if req.Bedrooms != nil {
		residence.Bedrooms = req.Bedrooms
	}
	if req.Bathrooms != nil {
		d := decimal.NewFromFloat(*req.Bathrooms)
		residence.Bathrooms = &d
	}
	if req.SquareFootage != nil {
		residence.SquareFootage = req.SquareFootage
	}
	if req.YearBuilt != nil {
		residence.YearBuilt = req.YearBuilt
	}

	if err := h.db.Create(&residence).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create residence"})
	}

	h.db.Preload("Owner").Preload("PropertyType").First(&residence, residence.ID)
	return c.JSON(http.StatusCreated, h.toResidenceResponse(&residence))
}

// Delete handles DELETE /api/admin/residences/:id
func (h *AdminResidenceHandler) Delete(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid residence ID"})
	}

	var residence models.Residence
	if err := h.db.First(&residence, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Residence not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch residence"})
	}

	// Soft delete
	residence.IsActive = false
	if err := h.db.Save(&residence).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete residence"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Residence deactivated successfully"})
}

// BulkDelete handles DELETE /api/admin/residences/bulk
func (h *AdminResidenceHandler) BulkDelete(c echo.Context) error {
	var req dto.BulkDeleteRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	// Soft delete - deactivate all
	if err := h.db.Model(&models.Residence{}).Where("id IN ?", req.IDs).Update("is_active", false).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete residences"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Residences deactivated successfully", "count": len(req.IDs)})
}

func (h *AdminResidenceHandler) toResidenceResponse(res *models.Residence) dto.ResidenceResponse {
	// User count = owner (1) + shared users
	userCount := 1 + len(res.Users)

	response := dto.ResidenceResponse{
		ID:             res.ID,
		Name:           res.Name,
		OwnerID:        res.OwnerID,
		PropertyTypeID: res.PropertyTypeID,
		StreetAddress:  res.StreetAddress,
		ApartmentUnit:  res.ApartmentUnit,
		City:           res.City,
		StateProvince:  res.StateProvince,
		PostalCode:     res.PostalCode,
		Country:        res.Country,
		Description:    res.Description,
		IsPrimary:      res.IsPrimary,
		IsActive:       res.IsActive,
		UserCount:      userCount,
		CreatedAt:      res.CreatedAt.Format("2006-01-02T15:04:05Z"),
		UpdatedAt:      res.UpdatedAt.Format("2006-01-02T15:04:05Z"),
	}

	if res.Owner.ID != 0 {
		response.OwnerName = res.Owner.Username
	}
	if res.PropertyType != nil {
		response.PropertyType = &res.PropertyType.Name
	}
	if res.Bedrooms != nil {
		response.Bedrooms = res.Bedrooms
	}
	if res.Bathrooms != nil {
		f, _ := res.Bathrooms.Float64()
		response.Bathrooms = &f
	}
	if res.SquareFootage != nil {
		response.SquareFootage = res.SquareFootage
	}
	if res.LotSize != nil {
		f, _ := res.LotSize.Float64()
		response.LotSize = &f
	}
	if res.YearBuilt != nil {
		response.YearBuilt = res.YearBuilt
	}
	if res.PurchaseDate != nil {
		purchaseDate := res.PurchaseDate.Format("2006-01-02")
		response.PurchaseDate = &purchaseDate
	}
	if res.PurchasePrice != nil {
		f, _ := res.PurchasePrice.Float64()
		response.PurchasePrice = &f
	}

	return response
}
