package observability

import (
	"context"
	"time"

	"code.justin.tv/eventbus/controlplane/internal/db"
	"go.uber.org/zap"
)

func (o *ObservabilityDB) IAMRoleCreate(ctx context.Context, iamRole *db.IAMRole) (int, error) {
	var id int
	var err error
	o.observe(ctx, "IAMRoleCreate",
		func() ([]zap.Field, error) {
			id, err = o.db.IAMRoleCreate(ctx, iamRole)
			cpy := *iamRole
			cpy.ID = id
			return []zap.Field{
				zap.Object("iamRole", cpy),
			}, err
		},
	)
	return id, err
}

func (o *ObservabilityDB) IAMRoleUpdate(ctx context.Context, id int, editable *db.IAMRoleEditable) (int, error) {
	var err error
	o.observe(ctx, "IAMRoleUpdate",
		func() ([]zap.Field, error) {
			id, err = o.db.IAMRoleUpdate(ctx, id, editable)
			cpy := *editable
			cpyID := id
			return []zap.Field{
				zap.Int("id", cpyID),
				zap.Object("update", &cpy),
			}, err
		},
	)
	return id, err
}

func (o *ObservabilityDB) IAMRoles(ctx context.Context) ([]*db.IAMRole, error) {
	var err error
	var iamRoles []*db.IAMRole
	o.observe(ctx, "IAMRoles",
		func() ([]zap.Field, error) {
			iamRoles, err = o.db.IAMRoles(ctx)
			return []zap.Field{}, err
		})
	return iamRoles, err
}

func (o *ObservabilityDB) IAMRolesByServiceID(ctx context.Context, serviceID int) ([]*db.IAMRole, error) {
	var err error
	var iamRoles []*db.IAMRole
	o.observe(ctx, "IAMRolesByServiceID",
		func() ([]zap.Field, error) {
			iamRoles, err = o.db.IAMRolesByServiceID(ctx, serviceID)
			return []zap.Field{
				zap.Int("serviceID", serviceID),
			}, err
		})
	return iamRoles, err
}

func (o *ObservabilityDB) IAMRoleByID(ctx context.Context, id int) (*db.IAMRole, error) {
	var err error
	var iamRole *db.IAMRole
	o.observe(ctx, "IAMRoleByID",
		func() ([]zap.Field, error) {
			iamRole, err = o.db.IAMRoleByID(ctx, id)
			return []zap.Field{
				zap.Int("id", id),
			}, err
		})
	return iamRole, err
}

func (o *ObservabilityDB) IAMRoleUpdateCloudformationStatus(ctx context.Context, id int, cloudformationStatus string) (int, error) {
	var retID int
	var err error
	o.observe(ctx, "IAMRoleUpdateCloudformationStatus",
		func() ([]zap.Field, error) {
			retID, err = o.db.IAMRoleUpdateCloudformationStatus(ctx, id, cloudformationStatus)
			return []zap.Field{
				zap.String("cloudformationStatus", cloudformationStatus),
				zap.Int("iamRoleID", retID),
			}, err
		},
	)
	return retID, err
}

func (o *ObservabilityDB) IAMRoleByARN(ctx context.Context, arn string) (*db.IAMRole, error) {
	var err error
	var iamRole *db.IAMRole
	o.observe(ctx, "IAMRoleByARN",
		func() ([]zap.Field, error) {
			iamRole, err = o.db.IAMRoleByARN(ctx, arn)
			return []zap.Field{
				zap.String("arn", arn),
			}, err
		})
	return iamRole, err
}

func (o *ObservabilityDB) IAMRoleDelete(ctx context.Context, lease db.AWSLease, id int) error {
	var err error
	o.observe(ctx, "IAMRoleDelete",
		func() ([]zap.Field, error) {
			err = o.db.IAMRoleDelete(ctx, lease, id)
			return []zap.Field{
				zap.Int("id", id),
				zap.Object("lease", lease),
			}, err
		})
	return err
}

func (o *ObservabilityDB) IAMRolesEditForService(ctx context.Context, serviceID int, desiredRoles db.IAMRolesEditable) (report *db.IAMRolesEditReport, err error) {
	o.observe(ctx, "IAMRolesEditForService",
		func() ([]zap.Field, error) {
			report, err = o.db.IAMRolesEditForService(ctx, serviceID, desiredRoles)
			return []zap.Field{
				zap.Int("serviceID", serviceID),
				zap.Object("desiredRoles", desiredRoles),
			}, err
		},
	)
	return report, err
}

func (o *ObservabilityDB) IAMRoleAcquireLease(ctx context.Context, resourceID int, timeout time.Duration) (db.AWSLease, context.Context, error) {
	var err error
	var awsLease db.AWSLease
	var retCtx context.Context
	o.observe(ctx, "IAMRoleAcquireLease",
		func() ([]zap.Field, error) {
			var fields []zap.Field
			awsLease, retCtx, err = o.db.IAMRoleAcquireLease(ctx, resourceID, timeout)
			if awsLease != nil {
				fields = append(fields, zap.Object("lease", awsLease))
			}
			return append(fields, zap.Int("id", resourceID)), err
		},
	)
	return awsLease, retCtx, err
}

func (o *ObservabilityDB) IAMRoleReleaseLease(lease db.AWSLease) error {
	return o.db.IAMRoleReleaseLease(lease)
}
