package repository

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/Wei-Shaw/sub2api/internal/service"
)

// userPlatformQuotaServiceAdapter 将 repository 层的 userPlatformQuotaRepository
// 适配为 service.UserPlatformQuotaRepository 接口（返回 *service.UserPlatformQuotaRecord）。
type userPlatformQuotaServiceAdapter struct {
	inner *userPlatformQuotaRepository
}

// NewUserPlatformQuotaServiceAdapter 将 UserPlatformQuotaRepository 实现包装为
// 满足 service.UserPlatformQuotaRepository 接口的适配器。
func NewUserPlatformQuotaServiceAdapter(repo UserPlatformQuotaRepository) service.UserPlatformQuotaRepository {
	impl, ok := repo.(*userPlatformQuotaRepository)
	if !ok {
		// 非标准实现（如测试 fake），通过通用适配器包装
		return &genericUserPlatformQuotaAdapter{inner: repo}
	}
	return &userPlatformQuotaServiceAdapter{inner: impl}
}

func (a *userPlatformQuotaServiceAdapter) GetByUserPlatform(ctx context.Context, userID int64, platform string) (*service.UserPlatformQuotaRecord, error) {
	rec, err := a.inner.GetByUserPlatform(ctx, userID, platform)
	if err != nil || rec == nil {
		return nil, err
	}
	return toServiceRecord(rec), nil
}

// IncrementUsageWithReset 原子累加 cost 到 (user, platform) 三个窗口的用量。
func (a *userPlatformQuotaServiceAdapter) IncrementUsageWithReset(ctx context.Context, userID int64, platform string, cost float64, now time.Time) error {
	return a.inner.IncrementUsageWithReset(ctx, userID, platform, cost, now)
}

// ListByUser 查询用户的所有平台配额记录。
func (a *userPlatformQuotaServiceAdapter) ListByUser(ctx context.Context, userID int64) ([]service.UserPlatformQuotaRecord, error) {
	rows, err := a.inner.ListByUser(ctx, userID)
	if err != nil {
		return nil, err
	}
	out := make([]service.UserPlatformQuotaRecord, len(rows))
	for i, r := range rows {
		out[i] = service.UserPlatformQuotaRecord{
			UserID:             r.UserID,
			Platform:           r.Platform,
			DailyLimitUSD:      r.DailyLimitUSD,
			WeeklyLimitUSD:     r.WeeklyLimitUSD,
			MonthlyLimitUSD:    r.MonthlyLimitUSD,
			DailyUsageUSD:      r.DailyUsageUSD,
			WeeklyUsageUSD:     r.WeeklyUsageUSD,
			MonthlyUsageUSD:    r.MonthlyUsageUSD,
			DailyWindowStart:   r.DailyWindowStart,
			WeeklyWindowStart:  r.WeeklyWindowStart,
			MonthlyWindowStart: r.MonthlyWindowStart,
		}
	}
	return out, nil
}

// BulkInsertInitial 将 service.UserPlatformQuotaRecord 切片转换后调用底层 repo。
func (a *userPlatformQuotaServiceAdapter) BulkInsertInitial(ctx context.Context, records []service.UserPlatformQuotaRecord) error {
	repoRecords := make([]UserPlatformQuotaRecord, len(records))
	for i, r := range records {
		repoRecords[i] = UserPlatformQuotaRecord{
			UserID:          r.UserID,
			Platform:        r.Platform,
			DailyLimitUSD:   r.DailyLimitUSD,
			WeeklyLimitUSD:  r.WeeklyLimitUSD,
			MonthlyLimitUSD: r.MonthlyLimitUSD,
		}
	}
	return a.inner.BulkInsertInitial(ctx, repoRecords)
}

// UpsertForUser 全量替换该用户所有平台限额。
func (a *userPlatformQuotaServiceAdapter) UpsertForUser(ctx context.Context, userID int64, records []service.UserPlatformQuotaRecord) error {
	repoRecords := toRepoRecords(records)
	return a.inner.UpsertForUser(ctx, userID, repoRecords)
}

// ResetExpiredWindow 转发至 repository.ResetExpiredWindow，并将 repository sentinel 包装为 service sentinel。
func (a *userPlatformQuotaServiceAdapter) ResetExpiredWindow(ctx context.Context, userID int64, platform string, window string, newStart time.Time) error {
	err := a.inner.ResetExpiredWindow(ctx, userID, platform, window, newStart)
	if errors.Is(err, ErrUserPlatformQuotaNotFound) {
		return fmt.Errorf("%w: %w", service.ErrUserPlatformQuotaNotFound, err)
	}
	return err
}

// BatchSnapshotUsage 转换 []service.UserPlatformQuotaSnapshot → []UserPlatformQuotaSnapshot，
// 调底层 repo，并将 repository FK sentinel 包装为 service sentinel。
func (a *userPlatformQuotaServiceAdapter) BatchSnapshotUsage(ctx context.Context, snapshots []service.UserPlatformQuotaSnapshot, now time.Time) error {
	repoSnaps := make([]UserPlatformQuotaSnapshot, len(snapshots))
	for i, s := range snapshots {
		repoSnaps[i] = UserPlatformQuotaSnapshot{
			UserID:             s.UserID,
			Platform:           s.Platform,
			DailyUsageUSD:      s.DailyUsageUSD,
			WeeklyUsageUSD:     s.WeeklyUsageUSD,
			MonthlyUsageUSD:    s.MonthlyUsageUSD,
			DailyWindowStart:   s.DailyWindowStart,
			WeeklyWindowStart:  s.WeeklyWindowStart,
			MonthlyWindowStart: s.MonthlyWindowStart,
		}
	}
	err := a.inner.BatchSnapshotUsage(ctx, repoSnaps, now)
	if errors.Is(err, ErrUserPlatformQuotaFKViolation) {
		return fmt.Errorf("%w: %v", service.ErrUserPlatformQuotaFKViolation, err)
	}
	return err
}

// genericUserPlatformQuotaAdapter 通过通用接口适配（用于测试 fake 或非标准实现）。
type genericUserPlatformQuotaAdapter struct {
	inner UserPlatformQuotaRepository
}

func (a *genericUserPlatformQuotaAdapter) GetByUserPlatform(ctx context.Context, userID int64, platform string) (*service.UserPlatformQuotaRecord, error) {
	rec, err := a.inner.GetByUserPlatform(ctx, userID, platform)
	if err != nil || rec == nil {
		return nil, err
	}
	return toServiceRecord(rec), nil
}

// IncrementUsageWithReset 原子累加 cost（通用 adapter 实现）。
func (a *genericUserPlatformQuotaAdapter) IncrementUsageWithReset(ctx context.Context, userID int64, platform string, cost float64, now time.Time) error {
	return a.inner.IncrementUsageWithReset(ctx, userID, platform, cost, now)
}

// ListByUser 查询用户的所有平台配额记录（通用 adapter 实现）。
func (a *genericUserPlatformQuotaAdapter) ListByUser(ctx context.Context, userID int64) ([]service.UserPlatformQuotaRecord, error) {
	rows, err := a.inner.ListByUser(ctx, userID)
	if err != nil {
		return nil, err
	}
	out := make([]service.UserPlatformQuotaRecord, len(rows))
	for i, r := range rows {
		out[i] = service.UserPlatformQuotaRecord{
			UserID:             r.UserID,
			Platform:           r.Platform,
			DailyLimitUSD:      r.DailyLimitUSD,
			WeeklyLimitUSD:     r.WeeklyLimitUSD,
			MonthlyLimitUSD:    r.MonthlyLimitUSD,
			DailyUsageUSD:      r.DailyUsageUSD,
			WeeklyUsageUSD:     r.WeeklyUsageUSD,
			MonthlyUsageUSD:    r.MonthlyUsageUSD,
			DailyWindowStart:   r.DailyWindowStart,
			WeeklyWindowStart:  r.WeeklyWindowStart,
			MonthlyWindowStart: r.MonthlyWindowStart,
		}
	}
	return out, nil
}

// BulkInsertInitial 将 service.UserPlatformQuotaRecord 切片转换后调用底层 generic repo。
func (a *genericUserPlatformQuotaAdapter) BulkInsertInitial(ctx context.Context, records []service.UserPlatformQuotaRecord) error {
	repoRecords := make([]UserPlatformQuotaRecord, len(records))
	for i, r := range records {
		repoRecords[i] = UserPlatformQuotaRecord{
			UserID:          r.UserID,
			Platform:        r.Platform,
			DailyLimitUSD:   r.DailyLimitUSD,
			WeeklyLimitUSD:  r.WeeklyLimitUSD,
			MonthlyLimitUSD: r.MonthlyLimitUSD,
		}
	}
	return a.inner.BulkInsertInitial(ctx, repoRecords)
}

// UpsertForUser 全量替换（通用 adapter 实现）。
func (a *genericUserPlatformQuotaAdapter) UpsertForUser(ctx context.Context, userID int64, records []service.UserPlatformQuotaRecord) error {
	repoRecords := toRepoRecords(records)
	return a.inner.UpsertForUser(ctx, userID, repoRecords)
}

// ResetExpiredWindow 转发至 repository.ResetExpiredWindow（通用 adapter），并包装 sentinel。
func (a *genericUserPlatformQuotaAdapter) ResetExpiredWindow(ctx context.Context, userID int64, platform string, window string, newStart time.Time) error {
	err := a.inner.ResetExpiredWindow(ctx, userID, platform, window, newStart)
	if errors.Is(err, ErrUserPlatformQuotaNotFound) {
		return fmt.Errorf("%w: %w", service.ErrUserPlatformQuotaNotFound, err)
	}
	return err
}

// BatchSnapshotUsage 转换 []service.UserPlatformQuotaSnapshot → []UserPlatformQuotaSnapshot（通用 adapter），
// 并将 repository FK sentinel 包装为 service sentinel。
func (a *genericUserPlatformQuotaAdapter) BatchSnapshotUsage(ctx context.Context, snapshots []service.UserPlatformQuotaSnapshot, now time.Time) error {
	repoSnaps := make([]UserPlatformQuotaSnapshot, len(snapshots))
	for i, s := range snapshots {
		repoSnaps[i] = UserPlatformQuotaSnapshot{
			UserID:             s.UserID,
			Platform:           s.Platform,
			DailyUsageUSD:      s.DailyUsageUSD,
			WeeklyUsageUSD:     s.WeeklyUsageUSD,
			MonthlyUsageUSD:    s.MonthlyUsageUSD,
			DailyWindowStart:   s.DailyWindowStart,
			WeeklyWindowStart:  s.WeeklyWindowStart,
			MonthlyWindowStart: s.MonthlyWindowStart,
		}
	}
	err := a.inner.BatchSnapshotUsage(ctx, repoSnaps, now)
	if errors.Is(err, ErrUserPlatformQuotaFKViolation) {
		return fmt.Errorf("%w: %v", service.ErrUserPlatformQuotaFKViolation, err)
	}
	return err
}

// toServiceRecord 将 repository.UserPlatformQuotaRecord 转换为 service.UserPlatformQuotaRecord。
func toServiceRecord(rec *UserPlatformQuotaRecord) *service.UserPlatformQuotaRecord {
	return &service.UserPlatformQuotaRecord{
		UserID:             rec.UserID,
		Platform:           rec.Platform,
		DailyLimitUSD:      rec.DailyLimitUSD,
		WeeklyLimitUSD:     rec.WeeklyLimitUSD,
		MonthlyLimitUSD:    rec.MonthlyLimitUSD,
		DailyUsageUSD:      rec.DailyUsageUSD,
		WeeklyUsageUSD:     rec.WeeklyUsageUSD,
		MonthlyUsageUSD:    rec.MonthlyUsageUSD,
		DailyWindowStart:   rec.DailyWindowStart,
		WeeklyWindowStart:  rec.WeeklyWindowStart,
		MonthlyWindowStart: rec.MonthlyWindowStart,
	}
}

// toRepoRecords 将 service.UserPlatformQuotaRecord 切片转换为 repository.UserPlatformQuotaRecord（含 limit 字段，含 usage/window_start）。
func toRepoRecords(records []service.UserPlatformQuotaRecord) []UserPlatformQuotaRecord {
	out := make([]UserPlatformQuotaRecord, len(records))
	for i, r := range records {
		out[i] = UserPlatformQuotaRecord{
			UserID:             r.UserID,
			Platform:           r.Platform,
			DailyLimitUSD:      r.DailyLimitUSD,
			WeeklyLimitUSD:     r.WeeklyLimitUSD,
			MonthlyLimitUSD:    r.MonthlyLimitUSD,
			DailyUsageUSD:      r.DailyUsageUSD,
			WeeklyUsageUSD:     r.WeeklyUsageUSD,
			MonthlyUsageUSD:    r.MonthlyUsageUSD,
			DailyWindowStart:   r.DailyWindowStart,
			WeeklyWindowStart:  r.WeeklyWindowStart,
			MonthlyWindowStart: r.MonthlyWindowStart,
		}
	}
	return out
}
