package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/rede5/gohorsejobs/backend/internal/api/middleware"
	"github.com/rede5/gohorsejobs/backend/internal/dto"
	"github.com/rede5/gohorsejobs/backend/internal/models"
)

// JobServiceInterface describes the service needed by JobHandler
type JobServiceInterface interface {
	GetJobs(filter dto.JobFilterQuery) ([]models.JobWithCompany, int, error)
	CreateJob(req dto.CreateJobRequest, createdBy string) (*models.Job, error)
	GetJobByID(id string) (*models.Job, error)
	UpdateJob(id string, req dto.UpdateJobRequest) (*models.Job, error)
	DeleteJob(id string) error
}

type JobHandler struct {
	Service JobServiceInterface
}

func NewJobHandler(service JobServiceInterface) *JobHandler {
	return &JobHandler{Service: service}
}

// GetJobs godoc
// @Summary      List all jobs
// @Description  Get a paginated list of job postings with optional filters
// @Tags         Jobs
// @Accept       json
// @Produce      json
// @Param        page       query    int     false  "Page number (default: 1)"
// @Param        limit      query    int     false  "Items per page (default: 10, max: 100)"
// @Param        companyId  query    string     false  "Filter by company ID"
// @Param        featured   query    bool    false  "Filter by featured status"
// @Success      200  {object}  dto.PaginatedResponse
// @Failure      500  {string}  string  "Internal Server Error"
// @Router       /api/v1/jobs [get]
func (h *JobHandler) GetJobs(w http.ResponseWriter, r *http.Request) {
	page, _ := strconv.Atoi(r.URL.Query().Get("page"))
	limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
	companyID := r.URL.Query().Get("companyId")
	isFeaturedStr := r.URL.Query().Get("featured")

	// Extraction of filters
	search := r.URL.Query().Get("q")
	location := r.URL.Query().Get("location")
	empType := r.URL.Query().Get("type")
	workMode := r.URL.Query().Get("workMode")

	filter := dto.JobFilterQuery{
		PaginationQuery: dto.PaginationQuery{
			Page:  page,
			Limit: limit,
		},
	}
	if companyID != "" {
		filter.CompanyID = &companyID
	}
	if isFeaturedStr == "true" {
		val := true
		filter.IsFeatured = &val
	}
	if search != "" {
		filter.Search = &search
	}
	if location != "" {
		filter.Location = &location
	}
	if empType != "" {
		filter.EmploymentType = &empType
	}
	if workMode != "" {
		filter.WorkMode = &workMode
	}

	jobs, total, err := h.Service.GetJobs(filter)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	response := dto.PaginatedResponse{
		Data: jobs,
		Pagination: dto.Pagination{
			Page:  page,
			Limit: limit,
			Total: total,
		},
	}

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

// CreateJob godoc
// @Summary      Create a new job
// @Description  Create a new job posting
// @Tags         Jobs
// @Accept       json
// @Produce      json
// @Param        job  body      dto.CreateJobRequest  true  "Job data"
// @Success      201  {object}  models.Job
// @Failure      400  {string}  string  "Bad Request"
// @Failure      401  {string}  string  "Unauthorized"
// @Failure      500  {string}  string  "Internal Server Error"
// @Router       /api/v1/jobs [post]
func (h *JobHandler) CreateJob(w http.ResponseWriter, r *http.Request) {
	fmt.Println("[CREATE_JOB DEBUG] === CreateJob Handler Started ===")

	var req dto.CreateJobRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		fmt.Printf("[CREATE_JOB ERROR] Failed to decode request body: %v\n", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	fmt.Printf("[CREATE_JOB DEBUG] Request received: title=%s, companyId=%s, status=%s\n", req.Title, req.CompanyID, req.Status)
	fmt.Printf("[CREATE_JOB DEBUG] Full request: %+v\n", req)

	// Extract UserID from context
	val := r.Context().Value(middleware.ContextUserID)
	fmt.Printf("[CREATE_JOB DEBUG] Context UserID value: %v (type: %T)\n", val, val)

	userID, ok := val.(string)
	if !ok || userID == "" {
		fmt.Printf("[CREATE_JOB ERROR] UserID extraction failed. ok=%v, userID='%s'\n", ok, userID)
		http.Error(w, "Unauthorized: User ID missing", http.StatusUnauthorized)
		return
	}

	fmt.Printf("[CREATE_JOB DEBUG] UserID extracted: %s\n", userID)
	fmt.Println("[CREATE_JOB DEBUG] Calling service.CreateJob...")

	job, err := h.Service.CreateJob(req, userID)
	if err != nil {
		fmt.Printf("[CREATE_JOB ERROR] Service.CreateJob failed: %v\n", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Printf("[CREATE_JOB DEBUG] Job created successfully! ID=%s\n", job.ID)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(job)
}

// GetJobByID godoc
// @Summary      Get job by ID
// @Description  Get a single job posting by its ID
// @Tags         Jobs
// @Accept       json
// @Produce      json
// @Param        id   path      string  true  "Job ID"
// @Success      200  {object}  models.Job
// @Failure      400  {string}  string  "Bad Request"
// @Failure      404  {string}  string  "Not Found"
// @Router       /api/v1/jobs/{id} [get]
func (h *JobHandler) GetJobByID(w http.ResponseWriter, r *http.Request) {
	id := r.PathValue("id")

	job, err := h.Service.GetJobByID(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

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

// UpdateJob godoc
// @Summary      Update a job
// @Description  Update an existing job posting
// @Tags         Jobs
// @Accept       json
// @Produce      json
// @Param        id   path      string                   true  "Job ID"
// @Param        job  body      dto.UpdateJobRequest  true  "Updated job data"
// @Success      200  {object}  models.Job
// @Failure      400  {string}  string  "Bad Request"
// @Failure      500  {string}  string  "Internal Server Error"
// @Router       /api/v1/jobs/{id} [put]
func (h *JobHandler) UpdateJob(w http.ResponseWriter, r *http.Request) {
	id := r.PathValue("id")

	var req dto.UpdateJobRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	job, err := h.Service.UpdateJob(id, req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

// DeleteJob godoc
// @Summary      Delete a job
// @Description  Delete a job posting
// @Tags         Jobs
// @Accept       json
// @Produce      json
// @Param        id   path      string  true  "Job ID"
// @Success      204  "No Content"
// @Failure      400  {string}  string  "Bad Request"
// @Failure      500  {string}  string  "Internal Server Error"
// @Router       /api/v1/jobs/{id} [delete]
func (h *JobHandler) DeleteJob(w http.ResponseWriter, r *http.Request) {
	id := r.PathValue("id")

	if err := h.Service.DeleteJob(id); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
