package handlers

import (
	"context"

	"github.com/gin-gonic/gin"
	"github.com/timetracker/backend/internal/api/dto"
	"github.com/timetracker/backend/internal/api/responses"
	"github.com/timetracker/backend/internal/api/utils"
	"github.com/timetracker/backend/internal/models"
	"github.com/timetracker/backend/internal/types"
)

// CompanyHandler handles company-related API endpoints
type CompanyHandler struct{}

// NewCompanyHandler creates a new CompanyHandler
func NewCompanyHandler() *CompanyHandler {
	return &CompanyHandler{}
}

// GetCompanies handles GET /companies
//
//	@Summary		Get all companies
//	@Description	Get a list of all companies
//	@Tags			companies
//	@Accept			json
//	@Produce		json
//	@Security		BearerAuth
//	@Success		200	{object}	utils.Response{data=[]dto.CompanyDto}
//	@Failure		401	{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		500	{object}	utils.Response{error=utils.ErrorInfo}
//	@Router			/companies [get]
func (h *CompanyHandler) GetCompanies(c *gin.Context) {
	utils.HandleGetAll(c, models.GetAllCompanies, convertCompanyToDTO, "companies")
}

// GetCompanyByID handles GET /companies/:id
//
//	@Summary		Get company by ID
//	@Description	Get a company by its ID
//	@Tags			companies
//	@Accept			json
//	@Produce		json
//	@Security		BearerAuth
//	@Param			id	path		string	true	"Company ID"
//	@Success		200	{object}	utils.Response{data=dto.CompanyDto}
//	@Failure		400	{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		401	{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		404	{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		500	{object}	utils.Response{error=utils.ErrorInfo}
//	@Router			/companies/{id} [get]
func (h *CompanyHandler) GetCompanyByID(c *gin.Context) {
	utils.HandleGetByID(c, models.GetCompanyByID, convertCompanyToDTO, "company")
}

// CreateCompany handles POST /companies
//
//	@Summary		Create a new company
//	@Description	Create a new company
//	@Tags			companies
//	@Accept			json
//	@Produce		json
//	@Security		BearerAuth
//	@Param			company	body		dto.CompanyCreateDto	true	"Company data"
//	@Success		201		{object}	utils.Response{data=dto.CompanyDto}
//	@Failure		400		{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		401		{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		500		{object}	utils.Response{error=utils.ErrorInfo}
//	@Router			/companies [post]
func (h *CompanyHandler) CreateCompany(c *gin.Context) {
	utils.HandleCreate(c, createCompanyWrapper, convertCompanyToDTO, "company")
}

// UpdateCompany handles PUT /companies/:id
//
//	@Summary		Update a company
//	@Description	Update an existing company
//	@Tags			companies
//	@Accept			json
//	@Produce		json
//	@Security		BearerAuth
//	@Param			id		path		string				true	"Company ID"
//	@Param			company	body		dto.CompanyUpdateDto	true	"Company data"
//	@Success		200		{object}	utils.Response{data=dto.CompanyDto}
//	@Failure		400		{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		401		{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		404		{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		500		{object}	utils.Response{error=utils.ErrorInfo}
//	@Router			/companies/{id} [put]
func (h *CompanyHandler) UpdateCompany(c *gin.Context) {
	utils.HandleUpdate(c, models.UpdateCompany, convertCompanyToDTO, prepareCompanyUpdate, "company")
}

// DeleteCompany handles DELETE /companies/:id
//
//	@Summary		Delete a company
//	@Description	Delete a company by its ID
//	@Tags			companies
//	@Accept			json
//	@Produce		json
//	@Security		BearerAuth
//	@Param			id	path		string	true	"Company ID"
//	@Success		204	{object}	utils.Response
//	@Failure		400	{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		401	{object}	utils.Response{error=utils.ErrorInfo}
//	@Failure		500	{object}	utils.Response{error=utils.ErrorInfo}
//	@Router			/companies/{id} [delete]
func (h *CompanyHandler) DeleteCompany(c *gin.Context) {
	utils.HandleDelete(c, models.DeleteCompany, "company")
}

// Helper functions for DTO conversion

func convertCompanyToDTO(company *models.Company) dto.CompanyDto {
	return dto.CompanyDto{
		ID:        company.ID.String(),
		CreatedAt: company.CreatedAt,
		UpdatedAt: company.UpdatedAt,
		Name:      company.Name,
	}
}

func convertCreateCompanyDTOToModel(dto dto.CompanyCreateDto) models.CompanyCreate {
	return models.CompanyCreate{
		Name: dto.Name,
	}
}

func convertUpdateCompanyDTOToModel(dto dto.CompanyUpdateDto, id types.ULID) models.CompanyUpdate {
	update := models.CompanyUpdate{
		ID: id,
	}

	if dto.Name != nil {
		update.Name = dto.Name
	}

	return update
}

// prepareCompanyUpdate prepares the company update object by parsing the ID, binding the JSON, and converting the DTO to a model
func prepareCompanyUpdate(c *gin.Context) (models.CompanyUpdate, error) {
	// Parse ID from URL
	id, err := utils.ParseID(c, "id")
	if err != nil {
		responses.BadRequestResponse(c, "Invalid company ID format")
		return models.CompanyUpdate{}, err
	}

	// Parse request body
	var companyUpdateDTO dto.CompanyUpdateDto
	if err := utils.BindJSON(c, &companyUpdateDTO); err != nil {
		responses.BadRequestResponse(c, err.Error())
		return models.CompanyUpdate{}, err
	}

	// Convert DTO to model
	return convertUpdateCompanyDTOToModel(companyUpdateDTO, id), nil
}

// createCompanyWrapper is a wrapper function for models.CreateCompany that takes a DTO as input
func createCompanyWrapper(ctx context.Context, createDTO dto.CompanyCreateDto) (*models.Company, error) {
	// Convert DTO to model
	companyCreate := convertCreateCompanyDTOToModel(createDTO)

	// Call the original function
	return models.CreateCompany(ctx, companyCreate)
}
