package handler

import (
	"encoding/json"
	"net/http"
	"time"

	"freeleaps.com/gitea-webhook-ambassador/internal/auth"
	"freeleaps.com/gitea-webhook-ambassador/internal/config"
	"freeleaps.com/gitea-webhook-ambassador/internal/database"
	"freeleaps.com/gitea-webhook-ambassador/internal/logger"
)

// ProjectHandler handles project mapping API endpoints
type ProjectHandler struct {
	db     *database.DB
	config *config.Configuration
	auth   *auth.Middleware
}

// NewProjectHandler creates a new project handler
func NewProjectHandler(db *database.DB, config *config.Configuration) *ProjectHandler {
	return &ProjectHandler{
		db:     db,
		config: config,
		auth:   auth.NewMiddleware(config.Server.SecretKey),
	}
}

// ProjectMappingRequest represents a request to create/update a project mapping
type ProjectMappingRequest struct {
	RepositoryName string `json:"repository_name"`
	DefaultJob     string `json:"default_job"`
	BranchJobs     []struct {
		BranchName string `json:"branch_name"`
		JobName    string `json:"job_name"`
	} `json:"branch_jobs"`
	BranchPatterns []struct {
		Pattern string `json:"pattern"`
		JobName string `json:"job_name"`
	} `json:"branch_patterns"`
}

// ProjectMappingResponse represents a project mapping response
type ProjectMappingResponse struct {
	ID             int64  `json:"id"`
	RepositoryName string `json:"repository_name"`
	DefaultJob     string `json:"default_job"`
	BranchJobs     []struct {
		ID         int64     `json:"id"`
		BranchName string    `json:"branch_name"`
		JobName    string    `json:"job_name"`
		CreatedAt  time.Time `json:"created_at"`
		UpdatedAt  time.Time `json:"updated_at"`
	} `json:"branch_jobs"`
	BranchPatterns []struct {
		ID        int64     `json:"id"`
		Pattern   string    `json:"pattern"`
		JobName   string    `json:"job_name"`
		CreatedAt time.Time `json:"created_at"`
		UpdatedAt time.Time `json:"updated_at"`
	} `json:"branch_patterns"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

// verifyAuth verifies the JWT token in the request
func (h *ProjectHandler) verifyAuth(r *http.Request) error {
	return h.auth.VerifyToken(r)
}

// HandleCreateProjectMapping handles the creation of project mappings
func (h *ProjectHandler) HandleCreateProjectMapping(w http.ResponseWriter, r *http.Request) {
	// Verify JWT token
	if err := h.verifyAuth(r); err != nil {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	// Parse request
	var req ProjectMappingRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	// Validate request
	if req.RepositoryName == "" {
		http.Error(w, "Repository name is required", http.StatusBadRequest)
		return
	}

	// Create project mapping
	project := &database.ProjectMapping{
		RepositoryName: req.RepositoryName,
		DefaultJob:     req.DefaultJob,
	}

	// Add branch jobs
	for _, job := range req.BranchJobs {
		project.BranchJobs = append(project.BranchJobs, database.BranchJob{
			BranchName: job.BranchName,
			JobName:    job.JobName,
		})
	}

	// Add branch patterns
	for _, pattern := range req.BranchPatterns {
		project.BranchPatterns = append(project.BranchPatterns, database.BranchPattern{
			Pattern: pattern.Pattern,
			JobName: pattern.JobName,
		})
	}

	if err := h.db.CreateProjectMapping(project); err != nil {
		logger.Error("Failed to create project mapping: %v", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
}

// HandleGetProjectMapping handles retrieving project mappings
func (h *ProjectHandler) HandleGetProjectMapping(w http.ResponseWriter, r *http.Request) {
	// Verify JWT token
	if err := h.verifyAuth(r); err != nil {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	// Get repository name from URL
	repoName := r.URL.Query().Get("repository")
	if repoName == "" {
		http.Error(w, "Repository name is required", http.StatusBadRequest)
		return
	}

	// Get project mapping
	project, err := h.db.GetProjectMapping(repoName)
	if err != nil {
		logger.Error("Failed to get project mapping: %v", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}
	if project == nil {
		http.Error(w, "Project mapping not found", http.StatusNotFound)
		return
	}

	// Convert to response format
	response := ProjectMappingResponse{
		ID:             project.ID,
		RepositoryName: project.RepositoryName,
		DefaultJob:     project.DefaultJob,
		CreatedAt:      project.CreatedAt,
		UpdatedAt:      project.UpdatedAt,
	}

	for _, job := range project.BranchJobs {
		response.BranchJobs = append(response.BranchJobs, struct {
			ID         int64     `json:"id"`
			BranchName string    `json:"branch_name"`
			JobName    string    `json:"job_name"`
			CreatedAt  time.Time `json:"created_at"`
			UpdatedAt  time.Time `json:"updated_at"`
		}{
			ID:         job.ID,
			BranchName: job.BranchName,
			JobName:    job.JobName,
			CreatedAt:  job.CreatedAt,
			UpdatedAt:  job.UpdatedAt,
		})
	}

	for _, pattern := range project.BranchPatterns {
		response.BranchPatterns = append(response.BranchPatterns, struct {
			ID        int64     `json:"id"`
			Pattern   string    `json:"pattern"`
			JobName   string    `json:"job_name"`
			CreatedAt time.Time `json:"created_at"`
			UpdatedAt time.Time `json:"updated_at"`
		}{
			ID:        pattern.ID,
			Pattern:   pattern.Pattern,
			JobName:   pattern.JobName,
			CreatedAt: pattern.CreatedAt,
			UpdatedAt: pattern.UpdatedAt,
		})
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}
