package serviceparts

import (
	"fmt"
	"strconv"
	"strings"
	"system-altrak/internal/domain"
	"system-altrak/internal/dto"
	"system-altrak/internal/middleware"
	"system-altrak/pkg/utils"

	"github.com/gofiber/fiber/v2"
)

type Handler struct {
	service ServicePartsService
}

func NewHandler(s ServicePartsService) *Handler {
	return &Handler{service: s}
}

func (h *Handler) CreateServiceParts(c *fiber.Ctx) error {
	var req dto.MemoServicePartsRequest
	if err := c.BodyParser(&req); err != nil {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid requisition data structure format")
	}

	middleware.SanitizeStruct(&req)

	result := utils.ValidateStructDetailed(req)
	if !result.IsValid {
		return utils.ValidationErrorResponse(c, "Validation failed", result.Errors)
	}

	parts := buildMemoServiceParts(req)

	branchID, _ := c.Locals("current_branch_id").(uint)
	if err := h.service.CreateAuthorization(&parts, branchID); err != nil {
		return utils.InternalErrorResponse(c, err.Error())
	}
	return utils.SuccessResponse(c, "Service Parts synchronized successfully", parts)
}

func (h *Handler) UpdateServiceParts(c *fiber.Ctx) error {
	id, err := utils.ParseParamID(c, "id")
	if err != nil {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid ID parameter")
	}

	var req dto.MemoServicePartsRequest
	if err := c.BodyParser(&req); err != nil {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid requisition data structure format")
	}

	middleware.SanitizeStruct(&req)

	result := utils.ValidateStructDetailed(req)
	if !result.IsValid {
		return utils.ValidationErrorResponse(c, "Validation failed", result.Errors)
	}

	parts := buildMemoServiceParts(req)
	parts.ID = id

	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	if err := h.service.UpdateAuthorization(&parts, branchID, role); err != nil {
		return utils.InternalErrorResponse(c, err.Error())
	}
	return utils.SuccessResponse(c, "Service Parts updated successfully", parts)
}

func (h *Handler) ListServiceParts(c *fiber.Ctx) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	list, err := h.service.ListServiceParts(branchID, role)
	if err != nil {
		return utils.InternalErrorResponse(c, "Failed to load SR list")
	}
	return utils.SuccessResponse(c, "OK", list)
}

func (h *Handler) GetServiceParts(c *fiber.Ctx) error {
	id, err := utils.ParseParamID(c, "id")
	if err != nil {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid ID parameter")
	}
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	parts, err := h.service.GetServiceParts(id, branchID, role)
	if err != nil {
		return utils.NotFoundResponse(c, "Service Parts")
	}
	return utils.SuccessResponse(c, "Service Parts localized successfully", parts)
}

func (h *Handler) ExportExcel(c *fiber.Ctx) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)

	tab := utils.NormalizeTab("serviceparts", c.Query("tab", "all"), "all")
	if tab != "all" && tab != "draft" && tab != "completed" {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid tab filter. Allowed values: all, draft, completed (or verified alias)")
	}

	search := strings.TrimSpace(c.Query("search", ""))

	reader, err := h.service.ExportSRToExcel(branchID, role, tab, search)
	if err != nil {
		return utils.InternalErrorResponse(c, err.Error())
	}

	c.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Set("Content-Disposition", "attachment; filename=Service_Parts_List.xlsx")
	return c.SendStream(reader)
}

func (h *Handler) DownloadExport(c *fiber.Ctx) error {
	idRaw := strings.TrimSpace(c.Query("id"))
	if idRaw == "" {
		idRaw = strings.TrimSpace(c.Params("id"))
	}
	if idRaw == "" {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid ID parameter")
	}

	parsedID, err := strconv.ParseUint(idRaw, 10, 32)
	if err != nil || parsedID == 0 {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid ID parameter")
	}
	id := uint(parsedID)

	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	buf, ref, err := h.service.GeneratePDF(id, branchID, role)
	if err != nil {
		return utils.InternalErrorResponse(c, err.Error())
	}

	c.Set("Content-Type", "application/pdf")
	c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=REQ-%s.pdf", ref))
	return c.Send(buf)
}

func (h *Handler) DeleteServiceParts(c *fiber.Ctx) error {
	id, err := utils.ParseParamID(c, "id")
	if err != nil {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid ID parameter")
	}
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	if err := h.service.DeleteServiceParts(id, branchID, role); err != nil {
		return utils.InternalErrorResponse(c, "Failed to purge service requisition")
	}
	return utils.SuccessResponse(c, "Service Parts purged successfully", nil)
}

func buildMemoServiceParts(req dto.MemoServicePartsRequest) domain.MemoServiceParts {
	return domain.MemoServiceParts{
		ChargeTo:          req.ChargeTo,
		CC:                req.CC,
		Customer:          req.Customer,
		EquipmentLocation: req.EquipmentLocation,
		SalesAgreementNo:  req.SalesAgreementNo,
		Description:       req.Description,
		Status:            req.Status,
		EngineUnit:        req.EngineUnit,
		ESNNumber:         req.ESNNumber,
		SpvName:           req.SpvName,
		SpvPosition:       req.SpvPosition,
		Subject:           req.Subject,
		To:                req.To,
		From:              req.From,
		Checklist:         buildMemoServicePartsChecklist(req.Checklist),
		Equipments:        buildMemoServicePartsEquipments(req.Equipments),
	}
}

func buildMemoServicePartsChecklist(req *dto.MemoServicePartsChecklistRequest) *domain.MemoServicePartsChecklist {
	if req == nil {
		return nil
	}

	return &domain.MemoServicePartsChecklist{
		PreDeliveryCheck:    req.PreDeliveryCheck,
		DeliveryCheck:       req.DeliveryCheck,
		PeriodicMaintenance: req.PeriodicMaintenance,
		Repair:              req.Repair,
		Assemble:            req.Assemble,
		Recondition:         req.Recondition,
		Training:            req.Training,
		Other:               req.Other,
		Unit:                req.Unit,
		PanelCabel:          req.PanelCabel,
		FuelTank:            req.FuelTank,
		ExhaustSystem:       req.ExhaustSystem,
		FrontAttachment:     req.FrontAttachment,
		RearAttachment:      req.RearAttachment,
		Manuals:             req.Manuals,
		Others:              req.Others,
	}
}

func buildMemoServicePartsEquipments(req []dto.MemoServicePartsEquipmentRequest) []domain.MemoServicePartsEquipment {
	if len(req) == 0 {
		return nil
	}

	equipments := make([]domain.MemoServicePartsEquipment, 0, len(req))
	for _, item := range req {
		equipments = append(equipments, domain.MemoServicePartsEquipment{
			No:           item.No,
			Brand:        item.Brand,
			Model:        item.Model,
			SerialNumber: item.SerialNumber,
			Qty:          item.Qty,
			MHPNo:        item.MHPNo,
			TableBlock:   item.TableBlock,
		})
	}

	return equipments
}
