package handlers

import (
	"net/http"
	"strconv"

	"github.com/labstack/echo/v4"

	"github.com/treytartt/honeydue-api/internal/apperrors"
	"github.com/treytartt/honeydue-api/internal/dto/requests"
	"github.com/treytartt/honeydue-api/internal/i18n"
	"github.com/treytartt/honeydue-api/internal/middleware"
	"github.com/treytartt/honeydue-api/internal/services"
	"github.com/treytartt/honeydue-api/internal/validator"
)

// ResidenceHandler handles residence-related HTTP requests
type ResidenceHandler struct {
	residenceService  *services.ResidenceService
	pdfService        *services.PDFService
	emailService      *services.EmailService
	pdfReportsEnabled bool
}

// NewResidenceHandler creates a new residence handler
func NewResidenceHandler(residenceService *services.ResidenceService, pdfService *services.PDFService, emailService *services.EmailService, pdfReportsEnabled bool) *ResidenceHandler {
	return &ResidenceHandler{
		residenceService:  residenceService,
		pdfService:        pdfService,
		emailService:      emailService,
		pdfReportsEnabled: pdfReportsEnabled,
	}
}

// ListResidences handles GET /api/residences/
func (h *ResidenceHandler) ListResidences(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	response, err := h.residenceService.ListResidences(user.ID)
	if err != nil {
		return err
	}

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

// GetMyResidences handles GET /api/residences/my-residences/
func (h *ResidenceHandler) GetMyResidences(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}
	userNow := middleware.GetUserNow(c)

	response, err := h.residenceService.GetMyResidences(user.ID, userNow)
	if err != nil {
		return err
	}

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

// GetSummary handles GET /api/residences/summary/
// Returns just the task statistics summary without full residence data
func (h *ResidenceHandler) GetSummary(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}
	userNow := middleware.GetUserNow(c)

	summary, err := h.residenceService.GetSummary(user.ID, userNow)
	if err != nil {
		return err
	}

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

// GetResidence handles GET /api/residences/:id/
func (h *ResidenceHandler) GetResidence(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	userNow := middleware.GetUserNow(c)
	response, err := h.residenceService.GetResidence(uint(residenceID), user.ID, userNow)
	if err != nil {
		return err
	}

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

// CreateResidence handles POST /api/residences/
func (h *ResidenceHandler) CreateResidence(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	var req requests.CreateResidenceRequest
	if err := c.Bind(&req); err != nil {
		return apperrors.BadRequest("error.invalid_request")
	}
	if err := c.Validate(&req); err != nil {
		return c.JSON(http.StatusBadRequest, validator.FormatValidationErrors(err))
	}

	response, err := h.residenceService.CreateResidence(&req, user.ID)
	if err != nil {
		return err
	}

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

// UpdateResidence handles PUT/PATCH /api/residences/:id/
func (h *ResidenceHandler) UpdateResidence(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	var req requests.UpdateResidenceRequest
	if err := c.Bind(&req); err != nil {
		return apperrors.BadRequest("error.invalid_request")
	}
	if err := c.Validate(&req); err != nil {
		return c.JSON(http.StatusBadRequest, validator.FormatValidationErrors(err))
	}

	response, err := h.residenceService.UpdateResidence(uint(residenceID), user.ID, &req)
	if err != nil {
		return err
	}

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

// DeleteResidence handles DELETE /api/residences/:id/
func (h *ResidenceHandler) DeleteResidence(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	response, err := h.residenceService.DeleteResidence(uint(residenceID), user.ID)
	if err != nil {
		return err
	}

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

// GetShareCode handles GET /api/residences/:id/share-code/
// Returns the active share code for a residence, or null if none exists
func (h *ResidenceHandler) GetShareCode(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	shareCode, err := h.residenceService.GetShareCode(uint(residenceID), user.ID)
	if err != nil {
		return err
	}

	if shareCode == nil {
		return c.JSON(http.StatusOK, map[string]interface{}{"share_code": nil})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"share_code": shareCode})
}

// GenerateShareCode handles POST /api/residences/:id/generate-share-code/
func (h *ResidenceHandler) GenerateShareCode(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	var req requests.GenerateShareCodeRequest
	// Request body is optional
	c.Bind(&req)

	response, err := h.residenceService.GenerateShareCode(uint(residenceID), user.ID, req.ExpiresInHours)
	if err != nil {
		return err
	}

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

// GenerateSharePackage handles POST /api/residences/:id/generate-share-package/
// Returns a share code with metadata for creating a .honeydue package file
func (h *ResidenceHandler) GenerateSharePackage(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	var req requests.GenerateShareCodeRequest
	// Request body is optional (for expires_in_hours)
	c.Bind(&req)

	response, err := h.residenceService.GenerateSharePackage(uint(residenceID), user.ID, req.ExpiresInHours)
	if err != nil {
		return err
	}

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

// JoinWithCode handles POST /api/residences/join-with-code/
func (h *ResidenceHandler) JoinWithCode(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	var req requests.JoinWithCodeRequest
	if err := c.Bind(&req); err != nil {
		return apperrors.BadRequest("error.invalid_request")
	}
	if err := c.Validate(&req); err != nil {
		return err
	}

	response, err := h.residenceService.JoinWithCode(req.Code, user.ID)
	if err != nil {
		return err
	}

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

// GetResidenceUsers handles GET /api/residences/:id/users/
func (h *ResidenceHandler) GetResidenceUsers(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	users, err := h.residenceService.GetResidenceUsers(uint(residenceID), user.ID)
	if err != nil {
		return err
	}

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

// RemoveResidenceUser handles DELETE /api/residences/:id/users/:user_id/
func (h *ResidenceHandler) RemoveResidenceUser(c echo.Context) error {
	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	userIDToRemove, err := strconv.ParseUint(c.Param("user_id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_user_id")
	}

	err = h.residenceService.RemoveUser(uint(residenceID), uint(userIDToRemove), user.ID)
	if err != nil {
		return err
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": i18n.LocalizedMessage(c, "message.user_removed")})
}

// GetResidenceTypes handles GET /api/residences/types/
func (h *ResidenceHandler) GetResidenceTypes(c echo.Context) error {
	types, err := h.residenceService.GetResidenceTypes()
	if err != nil {
		return err
	}

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

// GenerateTasksReport handles POST /api/residences/:id/generate-tasks-report/
// Generates a PDF report of tasks for the residence and emails it
func (h *ResidenceHandler) GenerateTasksReport(c echo.Context) error {
	if !h.pdfReportsEnabled {
		return apperrors.BadRequest("error.feature_disabled")
	}

	user, err := middleware.MustGetAuthUser(c)
	if err != nil {
		return err
	}

	residenceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return apperrors.BadRequest("error.invalid_residence_id")
	}

	// Optional request body for email recipient
	var req struct {
		Email string `json:"email"`
	}
	c.Bind(&req)

	// Generate the report data
	report, err := h.residenceService.GenerateTasksReport(uint(residenceID), user.ID)
	if err != nil {
		return err
	}

	// Determine recipient email
	recipientEmail := req.Email
	if recipientEmail == "" {
		recipientEmail = user.Email
	}

	// Get recipient name
	recipientName := user.FirstName
	if recipientName == "" {
		recipientName = user.Username
	}

	// Generate PDF if PDF service is available
	var pdfGenerated bool
	var emailSent bool
	if h.pdfService != nil && h.emailService != nil {
		pdfData, pdfErr := h.pdfService.GenerateTasksReportPDF(report)
		if pdfErr == nil {
			pdfGenerated = true

			// Send email with PDF attachment
			emailErr := h.emailService.SendTasksReportEmail(
				recipientEmail,
				recipientName,
				report.ResidenceName,
				report.TotalTasks,
				report.Completed,
				report.Pending,
				report.Overdue,
				pdfData,
			)
			if emailErr == nil {
				emailSent = true
			}
		}
	}

	// Build response message
	message := i18n.LocalizedMessage(c, "message.tasks_report_generated")
	if pdfGenerated && emailSent {
		message = i18n.LocalizedMessageWithData(c, "message.tasks_report_sent", map[string]interface{}{"Email": recipientEmail})
	} else if pdfGenerated && !emailSent {
		message = i18n.LocalizedMessage(c, "message.tasks_report_email_failed")
	}

	return c.JSON(http.StatusOK, map[string]interface{}{
		"message":         message,
		"residence_name":  report.ResidenceName,
		"recipient_email": recipientEmail,
		"pdf_generated":   pdfGenerated,
		"email_sent":      emailSent,
		"report":          report,
	})
}
