package service

import (
	"context"
	"time"

	"gorm.io/gorm"
)

const farmDepreciationSnapshotTable = "farm_depreciation_snapshots"

func NormalizeDateOnlyUTC(value time.Time) time.Time {
	if value.IsZero() {
		return value
	}
	v := value.UTC()
	return time.Date(v.Year(), v.Month(), v.Day(), 0, 0, 0, 0, time.UTC)
}

func MinNonZeroDateOnlyUTC(values ...time.Time) time.Time {
	var out time.Time
	for _, value := range values {
		if value.IsZero() {
			continue
		}
		normalized := NormalizeDateOnlyUTC(value)
		if out.IsZero() || normalized.Before(out) {
			out = normalized
		}
	}
	return out
}

func InvalidateFarmDepreciationSnapshotsFromDate(ctx context.Context, db *gorm.DB, farmIDs []uint, fromDate time.Time) error {
	if db == nil {
		return nil
	}
	if fromDate.IsZero() {
		return nil
	}

	fromDate = NormalizeDateOnlyUTC(fromDate)
	query := db.WithContext(ctx).
		Table(farmDepreciationSnapshotTable).
		Where("period_date >= ?", fromDate)
	if len(farmIDs) > 0 {
		query = query.Where("project_flock_id IN ?", farmIDs)
	}
	return query.Delete(nil).Error
}

func ResolveProjectFlockIDsByProjectFlockKandangIDs(ctx context.Context, db *gorm.DB, pfkIDs []uint) ([]uint, error) {
	if db == nil || len(pfkIDs) == 0 {
		return []uint{}, nil
	}

	var projectFlockIDs []uint
	if err := db.WithContext(ctx).
		Table("project_flock_kandangs").
		Distinct("project_flock_id").
		Where("id IN ?", pfkIDs).
		Pluck("project_flock_id", &projectFlockIDs).Error; err != nil {
		return nil, err
	}

	return projectFlockIDs, nil
}

func ResolveProjectFlockIDsByExpenseID(ctx context.Context, db *gorm.DB, expenseID uint) ([]uint, error) {
	if db == nil || expenseID == 0 {
		return []uint{}, nil
	}

	query := `
WITH direct_farms AS (
	SELECT DISTINCT pfk.project_flock_id
	FROM expense_nonstocks ens
	JOIN project_flock_kandangs pfk ON pfk.id = ens.project_flock_kandang_id
	WHERE ens.expense_id = @expense_id
),
json_farms AS (
	SELECT DISTINCT (jsonb_array_elements_text(e.project_flock_id::jsonb))::bigint AS project_flock_id
	FROM expenses e
	WHERE e.id = @expense_id
	  AND e.project_flock_id IS NOT NULL
)
SELECT DISTINCT project_flock_id
FROM (
	SELECT project_flock_id FROM direct_farms
	UNION ALL
	SELECT project_flock_id FROM json_farms
) x
`

	var ids []uint
	if err := db.WithContext(ctx).Raw(query, map[string]any{
		"expense_id": expenseID,
	}).Scan(&ids).Error; err != nil {
		return nil, err
	}

	return ids, nil
}
