package service

import (
	"context"
	"fmt"
	"strings"
	"time"

	commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	"gorm.io/gorm"
)

const (
	recordingLaneUsable    = "USABLE"
	recordingLaneStockable = "STOCKABLE"

	recordingFunctionStockOut     = "RECORDING_STOCK_OUT"
	recordingFunctionDepletionOut = "RECORDING_DEPLETION_OUT"
	recordingFunctionDepletionIn  = "RECORDING_DEPLETION_IN"
	recordingFunctionEggIn        = "RECORDING_EGG_IN"

	recordingSourceStocks     = "recording_stocks"
	recordingSourceDepletions = "recording_depletions"
	recordingSourceEggs       = "recording_eggs"
)

func (s *recordingService) reflowRecordingScope(
	ctx context.Context,
	tx *gorm.DB,
	productWarehouseID uint,
	recordingID uint,
	lane string,
	functionCode string,
	sourceTable string,
) error {
	if s == nil || s.FifoStockV2Svc == nil {
		return fmt.Errorf("FIFO v2 service is not available")
	}
	if tx == nil {
		return fmt.Errorf("transaction is required")
	}
	if productWarehouseID == 0 {
		return fmt.Errorf("product warehouse id is required")
	}

	flagGroupCode, err := resolveRecordingFlagGroupByProductWarehouse(ctx, tx, productWarehouseID, lane, functionCode, sourceTable)
	if err != nil {
		return err
	}
	if strings.TrimSpace(flagGroupCode) == "" {
		return fmt.Errorf("flag group code is not found for product warehouse %d", productWarehouseID)
	}

	asOf, err := resolveRecordingAsOf(ctx, tx, recordingID)
	if err != nil {
		return err
	}

	_, err = s.FifoStockV2Svc.Reflow(ctx, commonSvc.FifoStockV2ReflowRequest{
		FlagGroupCode:      flagGroupCode,
		ProductWarehouseID: productWarehouseID,
		AsOf:               asOf,
		Tx:                 tx,
	})
	return err
}

func resolveRecordingFlagGroupByProductWarehouse(
	ctx context.Context,
	tx *gorm.DB,
	productWarehouseID uint,
	lane string,
	functionCode string,
	sourceTable string,
) (string, error) {
	type row struct {
		FlagGroupCode string `gorm:"column:flag_group_code"`
	}

	var selected row
	q := tx.WithContext(ctx).
		Table("fifo_stock_v2_route_rules rr").
		Select("rr.flag_group_code").
		Joins("JOIN fifo_stock_v2_flag_groups fg ON fg.code = rr.flag_group_code AND fg.is_active = TRUE").
		Where("rr.is_active = TRUE").
		Where("rr.lane = ?", lane).
		Where("rr.source_table = ?", sourceTable)

	if strings.TrimSpace(functionCode) != "" {
		q = q.Where("rr.function_code = ?", functionCode)
	}

	err := q.
		Where(`
			EXISTS (
				SELECT 1
				FROM product_warehouses pw
				JOIN flags f ON f.flagable_id = pw.product_id
				JOIN fifo_stock_v2_flag_members fm ON fm.flag_name = f.name AND fm.is_active = TRUE
				WHERE pw.id = ?
				  AND f.flagable_type = ?
				  AND fm.flag_group_code = rr.flag_group_code
			)
		`, productWarehouseID, entity.FlagableTypeProduct).
		Order("rr.id ASC").
		Limit(1).
		Take(&selected).Error
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(selected.FlagGroupCode), nil
}

func resolveRecordingAsOf(ctx context.Context, tx *gorm.DB, recordingID uint) (*time.Time, error) {
	if recordingID == 0 {
		asOf := time.Now().UTC()
		return &asOf, nil
	}

	type row struct {
		RecordDatetime time.Time `gorm:"column:record_datetime"`
	}
	var selected row
	if err := tx.WithContext(ctx).
		Table("recordings").
		Select("record_datetime").
		Where("id = ?", recordingID).
		Limit(1).
		Take(&selected).Error; err != nil {
		return nil, err
	}

	asOf := selected.RecordDatetime.UTC()
	return &asOf, nil
}
