package handlers

import (
	"strconv"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
	"github.com/gofiber/fiber/v2"
)

type CreateCompanyReq struct {
	Name    string `json:"name" example:"CompanyName"`
	AdminID int64  `json:"admin_id" example:"1"`
}
type UpdateCompanyReq struct {
	Name    *string `json:"name,omitempty" example:"CompanyName"`
	AdminID *int64  `json:"admin_id,omitempty" example:"1"`
}

type CompanyRes struct {
	ID       int64  `json:"id" example:"1"`
	Name     string `json:"name" example:"CompanyName"`
	AdminID  int64  `json:"admin_id" example:"1"`
	WalletID int64  `json:"wallet_id" example:"1"`
}

type GetCompanyRes struct {
	ID               int64   `json:"id" example:"1"`
	Name             string  `json:"name" example:"CompanyName"`
	AdminID          int64   `json:"admin_id" example:"1"`
	WalletID         int64   `json:"wallet_id" example:"1"`
	WalletBalance    float32 `json:"balance" example:"1"`
	IsActive         bool    `json:"is_active" example:"false"`
	AdminFirstName   string  `json:"admin_first_name" example:"John"`
	AdminLastName    string  `json:"admin_last_name" example:"Doe"`
	AdminPhoneNumber string  `json:"admin_phone_number" example:"1234567890"`
}

func convertCompany(company domain.Company) CompanyRes {
	return CompanyRes{
		ID:       company.ID,
		Name:     company.Name,
		AdminID:  company.AdminID,
		WalletID: company.WalletID,
	}
}

func convertGetCompany(company domain.GetCompany) GetCompanyRes {
	return GetCompanyRes{
		ID:               company.ID,
		Name:             company.Name,
		AdminID:          company.AdminID,
		WalletID:         company.WalletID,
		WalletBalance:    company.WalletBalance.Float32(),
		IsActive:         company.IsWalletActive,
		AdminFirstName:   company.AdminFirstName,
		AdminLastName:    company.AdminLastName,
		AdminPhoneNumber: company.AdminPhoneNumber,
	}
}

// CreateCompany godoc
// @Summary Create a company
// @Description Creates a company
// @Tags company
// @Accept json
// @Produce json
// @Param createCompany body CreateCompanyReq true "Creates company"
// @Success 200 {object} CompanyRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /company [post]
func (h *Handler) CreateCompany(c *fiber.Ctx) error {
	var req CreateCompanyReq
	if err := c.BodyParser(&req); err != nil {
		h.logger.Error("CreateCompanyReq failed", "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
	}

	valErrs, ok := h.validator.Validate(c, req)
	if !ok {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
	}

	user, err := h.userSvc.GetUserByID(c.Context(), req.AdminID)
	if err != nil {
		h.logger.Error("Error fetching user", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get user", err, nil)
	}

	// Create Company Wallet
	newWallet, err := h.walletSvc.CreateWallet(c.Context(), domain.CreateWallet{
		IsWithdraw:     false,
		IsBettable:     true,
		IsTransferable: true,
		UserID:         req.AdminID,
	})

	if err != nil {
		h.logger.Error("Create Company Wallet failed", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create company wallet", err, nil)
	}

	company, err := h.companySvc.CreateCompany(c.Context(), domain.CreateCompany{
		Name:     req.Name,
		AdminID:  user.ID,
		WalletID: newWallet.ID,
	})

	if err != nil {
		h.logger.Error("CreateCompanyReq failed", "error", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "Internal server error",
		})
	}

	err = h.userSvc.UpdateUserCompany(c.Context(), user.ID, company.ID)
	if err != nil {
		h.logger.Error("CreateCompanyReq failed", "error", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "Internal server error",
		})
	}
	res := convertCompany(company)

	return response.WriteJSON(c, fiber.StatusCreated, "Company Created", res, nil)
}

// GetAllCompanies godoc
// @Summary Gets all companies
// @Description Gets all companies
// @Tags company
// @Accept json
// @Produce json
// @Success 200 {array} CompanyRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /company [get]
func (h *Handler) GetAllCompanies(c *fiber.Ctx) error {

	companies, err := h.companySvc.GetAllCompanies(c.Context())
	if err != nil {
		h.logger.Error("Failed to get companies", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get companies", err, nil)
	}

	var result []GetCompanyRes = make([]GetCompanyRes, 0, len(companies))

	for _, company := range companies {
		result = append(result, convertGetCompany(company))
	}

	return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil)

}

// GetCompanyByID godoc
// @Summary Gets company by id
// @Description Gets a single company by id
// @Tags company
// @Accept json
// @Produce json
// @Param id path int true "Company ID"
// @Success 200 {object} CompanyRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /company/{id} [get]
func (h *Handler) GetCompanyByID(c *fiber.Ctx) error {

	companyID := c.Params("id")
	id, err := strconv.ParseInt(companyID, 10, 64)
	if err != nil {
		h.logger.Error("Invalid company ID", "companyID", companyID, "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil)
	}

	company, err := h.companySvc.GetCompanyByID(c.Context(), id)

	if err != nil {
		h.logger.Error("Failed to get company by ID", "companyID", id, "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to company branch", err, nil)
	}

	res := convertGetCompany(company)

	return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil)

}

// GetAllCompanies godoc
// @Summary Gets all companies
// @Description Gets all companies
// @Tags company
// @Accept json
// @Produce json
// @Success 200 {array} CompanyRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /search/company [get]
func (h *Handler) SearchCompany(c *fiber.Ctx) error {
	searchQuery := c.Query("q")
	if searchQuery == "" {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Search query is required", nil, nil)
	}
	companies, err := h.companySvc.SearchCompanyByName(c.Context(), searchQuery)
	if err != nil {
		h.logger.Error("Failed to get companies", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get companies", err, nil)
	}

	var result []GetCompanyRes = make([]GetCompanyRes, 0, len(companies))

	for _, company := range companies {
		result = append(result, convertGetCompany(company))
	}

	return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil)

}

// UpdateCompany godoc
// @Summary Updates a company
// @Description Updates a company
// @Tags company
// @Accept json
// @Produce json
// @Param id path int true "Company ID"
// @Param updateCompany body UpdateCompanyReq true "Update Company"
// @Success 200 {object} CompanyRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /company/{id} [put]
func (h *Handler) UpdateCompany(c *fiber.Ctx) error {

	companyID := c.Params("id")
	id, err := strconv.ParseInt(companyID, 10, 64)
	if err != nil {
		h.logger.Error("Invalid company ID", "companyID", companyID, "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil)
	}

	var req UpdateCompanyReq
	if err := c.BodyParser(&req); err != nil {
		h.logger.Error("UpdateCompanyReq failed", "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
	}
	valErrs, ok := h.validator.Validate(c, req)
	if !ok {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
	}

	company, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
		ID:      id,
		Name:    req.Name,
		AdminID: req.AdminID,
	})

	if err != nil {
		h.logger.Error("Failed to update company", "companyID", id, "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update company", err, nil)
	}

	res := convertCompany(company)

	return response.WriteJSON(c, fiber.StatusOK, "Company Updated", res, nil)

}

// DeleteCompany godoc
// @Summary Delete the company
// @Description Delete the company
// @Tags company
// @Accept json
// @Produce json
// @Param id path int true "Company ID""
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /company/{id} [delete]
func (h *Handler) DeleteCompany(c *fiber.Ctx) error {

	companyID := c.Params("id")
	id, err := strconv.ParseInt(companyID, 10, 64)

	if err != nil {
		h.logger.Error("Invalid Company ID", "companyID", companyID, "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Company ID", err, nil)
	}

	err = h.companySvc.DeleteCompany(c.Context(), id)
	if err != nil {
		h.logger.Error("Failed to delete by ID", "Company ID", id, "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to Delete Company", err, nil)
	}

	return response.WriteJSON(c, fiber.StatusOK, "Company removed successfully", nil, nil)

}
