package handlers

import (
	"net/http"
	"strconv"

	"mohportal/middleware"
	"mohportal/models"
	"mohportal/services"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

var (
	tenantService   *services.TenantService
	userService     *services.UserService
	positionService *services.PositionService
	resumeService   *services.ResumeService
	applicationService *services.ApplicationService
)

// Initialize services
func init() {
	tenantService = &services.TenantService{}
	userService = &services.UserService{}
	positionService = &services.PositionService{}
	resumeService = &services.ResumeService{}
	applicationService = &services.ApplicationService{}
}

// HealthCheck returns the health status of the application
func HealthCheck(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"status":  "healthy",
		"message": "MerchantsOfHope.org recruiting platform is running",
		"service": "MOH Portal API",
	})
}

// Tenant Handlers
func CreateTenant(c *gin.Context) {
	var req struct {
		Name        string `json:"name" binding:"required"`
		Slug        string `json:"slug" binding:"required"`
		Description string `json:"description"`
		LogoURL     string `json:"logo_url"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	tenant, err := tenantService.CreateTenant(req.Name, req.Slug, req.Description, req.LogoURL)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusCreated, tenant)
}

func GetTenants(c *gin.Context) {
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
	
	tenants, err := tenantService.GetTenants(limit, offset)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, tenants)
}

func GetTenant(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tenant ID"})
		return
	}
	
	tenant, err := tenantService.GetTenant(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, tenant)
}

func UpdateTenant(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tenant ID"})
		return
	}
	
	var req struct {
		Name        string `json:"name"`
		Slug        string `json:"slug"`
		Description string `json:"description"`
		LogoURL     string `json:"logo_url"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	tenant, err := tenantService.UpdateTenant(id, req.Name, req.Slug, req.Description, req.LogoURL)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, tenant)
}

func DeleteTenant(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tenant ID"})
		return
	}
	
	if err := tenantService.DeleteTenant(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Tenant deleted successfully"})
}

// Auth Handlers
func Login(c *gin.Context) {
	var req struct {
		Email    string `json:"email" binding:"required,email"`
		Password string `json:"password" binding:"required"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	user, err := userService.AuthenticateUser(req.Email, req.Password)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
		return
	}
	
	// Generate JWT token (this is a simplified example)
	// In a real application, you'd use the jwt package to create a proper token
	
	// For now, return user info with a placeholder token
	c.JSON(http.StatusOK, gin.H{
		"message": "Login successful",
		"user":    user,
		"token":   "placeholder_token", // In real implementation, return actual JWT
	})
}

func Register(c *gin.Context) {
	var req struct {
		TenantID  string `json:"tenant_id" binding:"required"`
		Email     string `json:"email" binding:"required,email"`
		Username  string `json:"username" binding:"required"`
		FirstName string `json:"first_name" binding:"required"`
		LastName  string `json:"last_name" binding:"required"`
		Phone     string `json:"phone"`
		Role      string `json:"role" binding:"required"`
		Password  string `json:"password" binding:"required,min=8"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	tenantID, err := uuid.Parse(req.TenantID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tenant ID"})
		return
	}
	
	// Validate role
	if !models.ValidRole(req.Role) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role"})
		return
	}
	
	user, err := userService.CreateUser(tenantID, req.Email, req.Username, req.FirstName, req.LastName, req.Phone, req.Role, req.Password)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusCreated, gin.H{
		"message": "User registered successfully",
		"user":    user,
	})
}

func Logout(c *gin.Context) {
	middleware.LogoutHandler(c) // This will handle the response
}

func Profile(c *gin.Context) {
	// Get user from context (set by auth middleware)
	user, exists := c.Get("user")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{
		"user": user,
	})
}

// OIDC/Social Media Login
func OIDCLogin(c *gin.Context) {
	middleware.OIDCLoginHandler(c) // This will redirect the user
}

func OIDCCallback(c *gin.Context) {
	middleware.OIDCCallbackHandler(c) // This will handle the callback
}

func SocialLogin(c *gin.Context) {
	middleware.SocialLoginHandler(c) // This will redirect the user
}

func SocialCallback(c *gin.Context) {
	middleware.SocialCallbackHandler(c) // This will handle the callback
}

// Position Handlers
func GetPositions(c *gin.Context) {
	// Parse query parameters
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
	status := c.Query("status")
	employmentType := c.Query("employment_type")
	experienceLevel := c.Query("experience_level")
	location := c.Query("location")
	
	// Parse tenant ID if provided
	var tenantID *uuid.UUID
	if tenantStr := c.Query("tenant_id"); tenantStr != "" {
		id, err := uuid.Parse(tenantStr)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid tenant ID"})
			return
		}
		tenantID = &id
	}
	
	positions, err := positionService.GetPositions(tenantID, limit, offset, status, employmentType, experienceLevel, location)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, positions)
}

func GetPosition(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid position ID"})
		return
	}
	
	position, err := positionService.GetPosition(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, position)
}

func CreatePosition(c *gin.Context) {
	// Get user from context
	user, exists := c.Get("user")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}
	userData, ok := user.(models.User)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Error getting user data"})
		return
	}
	
	var req struct {
		Title           string   `json:"title" binding:"required"`
		Description     string   `json:"description" binding:"required"`
		Requirements    string   `json:"requirements"`
		Location        string   `json:"location"`
		EmploymentType  string   `json:"employment_type" binding:"required"`
		SalaryMin       *float64 `json:"salary_min"`
		SalaryMax       *float64 `json:"salary_max"`
		ExperienceLevel string   `json:"experience_level" binding:"required"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// Validate employment type
	if !models.ValidEmploymentType(req.EmploymentType) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid employment type"})
		return
	}
	
	// Validate experience level
	if !models.ValidExperienceLevel(req.ExperienceLevel) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid experience level"})
		return
	}
	
	// Validate salary range
	if req.SalaryMin != nil && req.SalaryMax != nil && *req.SalaryMin > *req.SalaryMax {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Minimum salary cannot be greater than maximum salary"})
		return
	}
	
	position, err := positionService.CreatePosition(userData.TenantID, userData.ID, req.Title, req.Description, req.Requirements, req.Location, req.EmploymentType, req.ExperienceLevel, req.SalaryMin, req.SalaryMax)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusCreated, position)
}

func UpdatePosition(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid position ID"})
		return
	}
	
	var req struct {
		Title           string   `json:"title" binding:"required"`
		Description     string   `json:"description" binding:"required"`
		Requirements    string   `json:"requirements"`
		Location        string   `json:"location"`
		EmploymentType  string   `json:"employment_type" binding:"required"`
		SalaryMin       *float64 `json:"salary_min"`
		SalaryMax       *float64 `json:"salary_max"`
		ExperienceLevel string   `json:"experience_level" binding:"required"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// Validate employment type
	if !models.ValidEmploymentType(req.EmploymentType) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid employment type"})
		return
	}
	
	// Validate experience level
	if !models.ValidExperienceLevel(req.ExperienceLevel) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid experience level"})
		return
	}
	
	// Validate salary range
	if req.SalaryMin != nil && req.SalaryMax != nil && *req.SalaryMin > *req.SalaryMax {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Minimum salary cannot be greater than maximum salary"})
		return
	}
	
	position, err := positionService.UpdatePosition(id, req.Title, req.Description, req.Requirements, req.Location, req.EmploymentType, req.ExperienceLevel, req.SalaryMin, req.SalaryMax)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, position)
}

func DeletePosition(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid position ID"})
		return
	}
	
	if err := positionService.DeletePosition(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Position deleted successfully"})
}

// Application Handlers
func GetApplications(c *gin.Context) {
	// Parse query parameters
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
	status := c.Query("status")
	
	// Parse user ID if provided
	var userID *uuid.UUID
	if userStr := c.Query("user_id"); userStr != "" {
		id, err := uuid.Parse(userStr)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
			return
		}
		userID = &id
	}
	
	// Parse position ID if provided
	var positionID *uuid.UUID
	if positionStr := c.Query("position_id"); positionStr != "" {
		id, err := uuid.Parse(positionStr)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid position ID"})
			return
		}
		positionID = &id
	}
	
	applications, err := applicationService.GetApplications(userID, positionID, status, limit, offset)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, applications)
}

func GetApplication(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid application ID"})
		return
	}
	
	application, err := applicationService.GetApplication(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, application)
}

func CreateApplication(c *gin.Context) {
	// Get user from context
	user, exists := c.Get("user")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}
	userData, ok := user.(models.User)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Error getting user data"})
		return
	}
	
	var req struct {
		PositionID  string `json:"position_id" binding:"required"`
		ResumeID    string `json:"resume_id"`
		CoverLetter string `json:"cover_letter"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	positionID, err := uuid.Parse(req.PositionID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid position ID"})
		return
	}
	
	var resumeID *uuid.UUID
	if req.ResumeID != "" {
		id, err := uuid.Parse(req.ResumeID)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid resume ID"})
			return
		}
		resumeID = &id
	}
	
	application, err := applicationService.CreateApplication(positionID, userData.ID, resumeID, req.CoverLetter)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusCreated, application)
}

func UpdateApplication(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid application ID"})
		return
	}
	
	// Get reviewer user from context
	reviewer, exists := c.Get("user")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}
	reviewerData, ok := reviewer.(models.User)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Error getting user data"})
		return
	}
	
	var req struct {
		Status string `json:"status" binding:"required"`
		Notes  string `json:"notes"`
	}
	
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// Validate status
	if !models.ValidStatus(req.Status) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid status"})
		return
	}
	
	application, err := applicationService.UpdateApplication(id, req.Status, reviewerData.ID, req.Notes)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, application)
}

func DeleteApplication(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid application ID"})
		return
	}
	
	if err := applicationService.DeleteApplication(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "Application deleted successfully"})
}

// Resume Handlers
func UploadResume(c *gin.Context) {
	// Get user from context
	user, exists := c.Get("user")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}
	userData, ok := user.(models.User)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Error getting user data"})
		return
	}
	
	title := c.PostForm("title")
	if title == "" {
		title = "Resume"
	}
	
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "File upload failed"})
		return
	}
	
	resume, err := resumeService.UploadResume(userData.ID, file, title)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	
	c.JSON(http.StatusCreated, resume)
}

func GetResume(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid resume ID"})
		return
	}
	
	// Get user from context
	user, exists := c.Get("user")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}
	userData, ok := user.(models.User)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Error getting user data"})
		return
	}
	
	resume, err := resumeService.GetResume(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	
	// Ensure the user owns the resume
	if resume.UserID != userData.ID {
		c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
		return
	}
	
	// Serve the file
	c.File(resume.FilePath)
}