package service

import (
	"context"
	"errors"
	"fmt"

	productWarehouseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
	warehouseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
	projectFlockKandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"

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

// Dipakai untuk semua module yang butuh cek:
// "PW ini → warehouse → kandang → project_flock_kandang sudah closing atau belum"
func EnsureProjectFlockNotClosedForProductWarehouses(
	ctx context.Context,
	db *gorm.DB,
	productWarehouseIDs []uint,
) error {
	if len(productWarehouseIDs) == 0 {
		return nil
	}

	pwRepo := productWarehouseRepo.NewProductWarehouseRepository(db)
	wRepo := warehouseRepo.NewWarehouseRepository(db)
	pfkRepo := projectFlockKandangRepo.NewProjectFlockKandangRepository(db)

	seenPW := make(map[uint]struct{})
	seenKandang := make(map[uint]struct{})

	for _, pwID := range productWarehouseIDs {
		if pwID == 0 {
			continue
		}
		if _, ok := seenPW[pwID]; ok {
			continue
		}
		seenPW[pwID] = struct{}{}

		pw, err := pwRepo.GetByID(ctx, pwID, nil)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return fiber.NewError(fiber.StatusBadRequest,
					fmt.Sprintf("Product warehouse %d tidak ditemukan", pwID))
			}
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product warehouse")
		}

		wh, err := wRepo.GetByID(ctx, uint(pw.WarehouseId), nil)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return fiber.NewError(fiber.StatusBadRequest,
					fmt.Sprintf("Warehouse %d tidak ditemukan", pw.WarehouseId))
			}
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate warehouse")
		}

		// Warehouse tanpa kandang → bukan kandang produksi → skip
		if wh.KandangId == nil || *wh.KandangId == 0 {
			continue
		}

		kandangID := uint(*wh.KandangId)
		if _, ok := seenKandang[kandangID]; ok {
			continue
		}
		seenKandang[kandangID] = struct{}{}

		pfk, err := pfkRepo.GetActiveByKandangID(ctx, kandangID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				// nggak ada project aktif untuk kandang ini → aman
				continue
			}
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate project flock")
		}
		// INTI RULE: kalau aktif tapi sudah punya ClosedAt → anggap "project sudah closing"
		if pfk != nil && pfk.ClosedAt != nil {
			return fiber.NewError(fiber.StatusBadRequest, "Project sudah closing")
		}
	}

	return nil
}

func EnsureProjectFlockNotClosedByProjectFlockKandangID(
	ctx context.Context,
	db *gorm.DB,
	pfkIDs []uint,
) error {
	pfkRepo := projectFlockKandangRepo.NewProjectFlockKandangRepository(db)

	seen := make(map[uint]struct{})
	for _, id := range pfkIDs {
		if id == 0 {
			continue
		}
		if _, ok := seen[id]; ok {
			continue
		}
		seen[id] = struct{}{}

		pfk, err := pfkRepo.GetByID(ctx, id)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return fiber.NewError(fiber.StatusBadRequest,
					fmt.Sprintf("Project flock kandang %d tidak ditemukan", id))
			}
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate project flock")
		}

		if pfk.ClosedAt != nil {
			return fiber.NewError(fiber.StatusBadRequest, "Project sudah closing")
		}
	}
	return nil
}
