package handlers

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

	"github.com/rede5/gohorsejobs/backend/internal/api/middleware"
	"github.com/rede5/gohorsejobs/backend/internal/core/dto"
	"github.com/rede5/gohorsejobs/backend/internal/core/usecases/auth"
	"github.com/rede5/gohorsejobs/backend/internal/core/usecases/tenant"
	"github.com/rede5/gohorsejobs/backend/internal/core/usecases/user"
)

type CoreHandlers struct {
	loginUC         *auth.LoginUseCase
	createCompanyUC *tenant.CreateCompanyUseCase
	createUserUC    *user.CreateUserUseCase
	listUsersUC     *user.ListUsersUseCase
	deleteUserUC    *user.DeleteUserUseCase
	listCompaniesUC *tenant.ListCompaniesUseCase
}

func NewCoreHandlers(l *auth.LoginUseCase, c *tenant.CreateCompanyUseCase, u *user.CreateUserUseCase, list *user.ListUsersUseCase, del *user.DeleteUserUseCase, lc *tenant.ListCompaniesUseCase) *CoreHandlers {
	return &CoreHandlers{
		loginUC:         l,
		createCompanyUC: c,
		createUserUC:    u,
		listUsersUC:     list,
		deleteUserUC:    del,
		listCompaniesUC: lc,
	}
}

// Login authenticates a user and returns a token.
// @Summary      User Login
// @Description  Authenticates a user by email and password. Returns JWT and user info.
// @Tags         Auth
// @Accept       json
// @Produce      json
// @Param        login  body      dto.LoginRequest  true  "Login Credentials"
// @Success      200    {object}  dto.AuthResponse
// @Failure      400    {string}  string "Invalid Request"
// @Failure      401    {string}  string "Unauthorized"
// @Router       /api/v1/auth/login [post]
func (h *CoreHandlers) Login(w http.ResponseWriter, r *http.Request) {
	var req dto.LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid Request", http.StatusBadRequest)
		return
	}

	resp, err := h.loginUC.Execute(r.Context(), req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

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

// CreateCompany registers a new tenant (Company) and its admin.
// @Summary      Create Company (Tenant)
// @Description  Registers a new company and creates an initial admin user.
// @Tags         Companies
// @Accept       json
// @Produce      json
// @Param        company  body      dto.CreateCompanyRequest  true  "Company Details"
// @Success      200      {object}  dto.CompanyResponse
// @Failure      400      {string}  string "Invalid Request"
// @Failure      500      {string}  string "Internal Server Error"
// @Router       /api/v1/companies [post]
func (h *CoreHandlers) CreateCompany(w http.ResponseWriter, r *http.Request) {
	var req dto.CreateCompanyRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid Request", http.StatusBadRequest)
		return
	}

	resp, err := h.createCompanyUC.Execute(r.Context(), req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

// ListCompanies returns all companies (superadmin or public depending on rule, usually superadmin).
// @Summary      List Companies
// @Description  Returns a list of all companies.
// @Tags         Companies
// @Accept       json
// @Produce      json
// @Success      200      {array}   dto.CompanyResponse
// @Failure      500      {string}  string "Internal Server Error"
// @Router       /api/v1/companies [get]
func (h *CoreHandlers) ListCompanies(w http.ResponseWriter, r *http.Request) {
	resp, err := h.listCompaniesUC.Execute(r.Context())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

// CreateUser creates a new user within the authenticated tenant.
// @Summary      Create User
// @Description  Creates a new user under the current tenant. Requires Admin role.
// @Tags         Users
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        user  body      dto.CreateUserRequest  true  "User Details"
// @Success      200   {object}  dto.UserResponse
// @Failure      400   {string}  string "Invalid Request"
// @Failure      403   {string}  string "Forbidden"
// @Failure      500   {string}  string "Internal Server Error"
// @Router       /api/v1/users [post]
func (h *CoreHandlers) CreateUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	tenantID, ok := ctx.Value(middleware.ContextTenantID).(string)
	if !ok || tenantID == "" {
		http.Error(w, "Tenant ID not found in context", http.StatusForbidden)
		return
	}

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

	resp, err := h.createUserUC.Execute(ctx, req, tenantID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

// ListUsers returns all users in the current tenant.
// @Summary      List Users
// @Description  Returns a list of users belonging to the authenticated tenant.
// @Tags         Users
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Success      200   {array}   dto.UserResponse
// @Failure      403   {string}  string "Forbidden"
// @Failure      500   {string}  string "Internal Server Error"
// @Router       /api/v1/users [get]
func (h *CoreHandlers) ListUsers(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	tenantID, ok := ctx.Value(middleware.ContextTenantID).(string)
	if !ok || tenantID == "" {
		http.Error(w, "Tenant ID not found in context", http.StatusForbidden)
		return
	}

	users, err := h.listUsersUC.Execute(ctx, tenantID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

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

// DeleteUser removes a user from the tenant.
// @Summary      Delete User
// @Description  Deletes a user by ID. Must belong to the same tenant.
// @Tags         Users
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id    path      string  true  "User ID"
// @Success      200   {string}  string "User deleted"
// @Failure      403   {string}  string "Forbidden"
// @Failure      500   {string}  string "Internal Server Error"
// @Router       /api/v1/users/{id} [delete]
func (h *CoreHandlers) DeleteUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	tenantID, ok := ctx.Value(middleware.ContextTenantID).(string)
	if !ok || tenantID == "" {
		http.Error(w, "Tenant ID not found in context", http.StatusForbidden)
		return
	}

	id := r.PathValue("id")
	if id == "" {
		// Fallback for older Go versions if PathValue not avail, though 1.22+ is standard now.
		// Usually we'd use a mux var. Since we use stdlib mux in 1.22:
		http.Error(w, "Missing User ID", http.StatusBadRequest)
		return
	}

	if err := h.deleteUserUC.Execute(ctx, id, tenantID); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{"message": "User deleted"})
}
