// Package state provides state management for AutoSSO.
// It defines the unified state storage interface and data structures
// for managing approval instances, pending removals, and processed instances.
//
// Requirements: 4.1
package state

import (
	"context"
	"time"
)

// Status constants for approval instances.
// These represent the lifecycle states of a permission approval.
const (
	// StatusPending indicates the approval is waiting for processing
	StatusPending = "pending"

	// StatusApproved indicates the approval has been processed and permissions granted
	StatusApproved = "approved"

	// StatusExpired indicates the permission has expired
	StatusExpired = "expired"

	// StatusRevoked indicates the permission has been revoked/removed
	StatusRevoked = "revoked"
)

// CloudType constants for identifying cloud platforms.
// These match the provider types defined in the provider package.
const (
	// CloudTypeAWS represents Amazon Web Services
	CloudTypeAWS = "AWS"

	// CloudTypeGCP represents Google Cloud Platform
	CloudTypeGCP = "GCP"

	// CloudTypeAzure represents Microsoft Azure
	CloudTypeAzure = "Azure"

	// CloudTypeAlibaba represents Alibaba Cloud
	CloudTypeAlibaba = "Alibaba"
)

// Store is the unified state storage interface.
// It provides methods for managing approval instances, pending removals,
// and tracking processed instances. Implementations can use MySQL (default)
// or file-based storage (backup option).
//
// The interface supports the following operations:
//   - Save/Get/List/Delete approval instances
//   - Save/Get/Delete pending permission removals
//   - Track processed (deleted) instances to avoid reprocessing
//
// Requirements: 4.1
type Store interface {
	// SaveInstance saves or updates an approval instance.
	// If an instance with the same ID exists, it will be updated.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - instance: The approval instance to save
	//
	// Returns:
	//   - error: Any error that occurred during the operation
	SaveInstance(ctx context.Context, instance *ApprovalInstance) error

	// GetInstance retrieves an approval instance by its ID.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - instanceID: The unique identifier of the instance
	//
	// Returns:
	//   - *ApprovalInstance: The retrieved instance, or nil if not found
	//   - error: Any error that occurred during the operation
	GetInstance(ctx context.Context, instanceID string) (*ApprovalInstance, error)

	// ListInstances retrieves approval instances matching the filter criteria.
	// If filter is nil, all instances are returned.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - filter: Optional filter criteria for the query
	//
	// Returns:
	//   - []*ApprovalInstance: List of matching instances
	//   - error: Any error that occurred during the operation
	ListInstances(ctx context.Context, filter *InstanceFilter) ([]*ApprovalInstance, error)

	// DeleteInstance removes an approval instance by its ID.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - instanceID: The unique identifier of the instance to delete
	//
	// Returns:
	//   - error: Any error that occurred during the operation
	DeleteInstance(ctx context.Context, instanceID string) error

	// SavePendingRemoval saves a pending permission removal record.
	// This is used to schedule permission revocation after the grace period.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - removal: The pending removal record to save
	//
	// Returns:
	//   - error: Any error that occurred during the operation
	SavePendingRemoval(ctx context.Context, removal *PendingRemoval) error

	// GetPendingRemovals retrieves all pending permission removal records.
	// These are permissions scheduled for revocation.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//
	// Returns:
	//   - []*PendingRemoval: List of pending removal records
	//   - error: Any error that occurred during the operation
	GetPendingRemovals(ctx context.Context) ([]*PendingRemoval, error)

	// DeletePendingRemoval removes a pending removal record by its ID.
	// This is called after the permission has been successfully revoked.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - id: The unique identifier of the pending removal record
	//
	// Returns:
	//   - error: Any error that occurred during the operation
	DeletePendingRemoval(ctx context.Context, id int64) error

	// SaveDeletedInstance marks an instance as processed/deleted.
	// This prevents the same instance from being processed again.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - instanceID: The unique identifier of the processed instance
	//
	// Returns:
	//   - error: Any error that occurred during the operation
	SaveDeletedInstance(ctx context.Context, instanceID string) error

	// IsInstanceDeleted checks if an instance has been processed/deleted.
	// This is used to skip already processed instances.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout
	//   - instanceID: The unique identifier of the instance to check
	//
	// Returns:
	//   - bool: True if the instance has been processed, false otherwise
	//   - error: Any error that occurred during the operation
	IsInstanceDeleted(ctx context.Context, instanceID string) (bool, error)

	// Close releases any resources held by the store.
	// This should be called when the store is no longer needed.
	//
	// Returns:
	//   - error: Any error that occurred during cleanup
	Close() error
}

// ApprovalInstance represents a Feishu approval instance for permission requests.
// It contains all the information about a permission approval, including
// the user, cloud account, permission sets, and time range.
//
// This structure replaces the data previously stored in instancesid.txt.
type ApprovalInstance struct {
	// ID is the unique identifier of the approval instance (from Feishu)
	ID string `db:"id" json:"id"`

	// Email is the email address of the user requesting permission
	Email string `db:"email" json:"email"`

	// AccountID is the cloud account/project/subscription ID
	AccountID string `db:"account_id" json:"account_id"`

	// PermissionSets is the list of permission set names requested
	// Stored as JSON in the database
	PermissionSets []string `db:"permission_sets" json:"permission_sets"`

	// StartTime is when the permission becomes effective
	StartTime time.Time `db:"start_time" json:"start_time"`

	// EndTime is when the permission expires
	EndTime time.Time `db:"end_time" json:"end_time"`

	// Status is the current status of the approval instance
	// Valid values: pending, approved, expired, revoked
	Status string `db:"status" json:"status"`

	// CloudType identifies the cloud platform
	// Valid values: AWS, GCP, Azure, Alibaba
	CloudType string `db:"cloud_type" json:"cloud_type"`

	// CreatedAt is when the record was created
	CreatedAt time.Time `db:"created_at" json:"created_at"`

	// UpdatedAt is when the record was last updated
	UpdatedAt time.Time `db:"updated_at" json:"updated_at"`

	// Description is the access resource description or reason
	Description string `db:"description" json:"description"`
}

// IsExpired checks if the approval instance has expired.
// An instance is considered expired if the current time is after EndTime.
func (a *ApprovalInstance) IsExpired() bool {
	return time.Now().After(a.EndTime)
}

// IsActive checks if the approval instance is currently active.
// An instance is active if the current time is between StartTime and EndTime,
// and the status is approved.
func (a *ApprovalInstance) IsActive() bool {
	now := time.Now()
	return a.Status == StatusApproved &&
		now.After(a.StartTime) &&
		now.Before(a.EndTime)
}

// DaysUntilExpiry returns the number of days until the instance expires.
// Returns 0 if already expired.
func (a *ApprovalInstance) DaysUntilExpiry() int {
	if a.IsExpired() {
		return 0
	}
	duration := time.Until(a.EndTime)
	return int(duration.Hours() / 24)
}

// DaysSinceExpiry returns the number of days since the instance expired.
// Returns 0 if not yet expired.
func (a *ApprovalInstance) DaysSinceExpiry() int {
	if !a.IsExpired() {
		return 0
	}
	duration := time.Since(a.EndTime)
	return int(duration.Hours() / 24)
}

// PendingRemoval represents a permission scheduled for removal.
// This is used to track permissions that have expired and are waiting
// for the grace period to pass before being revoked.
//
// This structure replaces the data previously stored in wait_delete_up.txt.
type PendingRemoval struct {
	// ID is the unique identifier of the pending removal record
	// Auto-generated by the database
	ID int64 `db:"id" json:"id"`

	// AccountID is the cloud account/project/subscription ID
	AccountID string `db:"account_id" json:"account_id"`

	// Email is the email address of the user whose permission will be removed
	Email string `db:"email" json:"email"`

	// PermissionSet is the name of the permission set to be removed
	PermissionSet string `db:"permission_set" json:"permission_set"`

	// CloudType identifies the cloud platform
	// Valid values: AWS, GCP, Azure, Alibaba
	CloudType string `db:"cloud_type" json:"cloud_type"`

	// ExpiredAt is when the permission expired
	ExpiredAt time.Time `db:"expired_at" json:"expired_at"`

	// ScheduledAt is when the permission is scheduled to be removed
	// This is typically ExpiredAt + grace period (e.g., 3 days)
	ScheduledAt time.Time `db:"scheduled_at" json:"scheduled_at"`

	// CreatedAt is when the record was created
	CreatedAt time.Time `db:"created_at" json:"created_at"`
}

// IsReadyForRemoval checks if the pending removal is ready to be processed.
// A removal is ready if the current time is after ScheduledAt.
func (p *PendingRemoval) IsReadyForRemoval() bool {
	return time.Now().After(p.ScheduledAt)
}

// DaysUntilRemoval returns the number of days until the scheduled removal.
// Returns 0 if already ready for removal.
func (p *PendingRemoval) DaysUntilRemoval() int {
	if p.IsReadyForRemoval() {
		return 0
	}
	duration := time.Until(p.ScheduledAt)
	return int(duration.Hours() / 24)
}

// InstanceFilter defines filter criteria for querying approval instances.
// All fields are optional; only non-zero values are used for filtering.
type InstanceFilter struct {
	// Status filters by approval status
	// Empty string means no status filter
	Status string

	// CloudType filters by cloud platform type
	// Empty string means no cloud type filter
	CloudType string

	// Email filters by user email address
	// Empty string means no email filter
	Email string

	// StartTime filters instances with StartTime >= this value
	// Zero time means no start time filter
	StartTime time.Time

	// EndTime filters instances with EndTime <= this value
	// Zero time means no end time filter
	EndTime time.Time

	// AccountID filters by cloud account ID
	// Empty string means no account filter
	AccountID string

	// Limit limits the number of results returned
	// Zero means no limit
	Limit int

	// Offset specifies the number of results to skip
	// Used for pagination
	Offset int
}

// IsEmpty checks if the filter has no criteria set.
func (f *InstanceFilter) IsEmpty() bool {
	if f == nil {
		return true
	}
	return f.Status == "" &&
		f.CloudType == "" &&
		f.Email == "" &&
		f.StartTime.IsZero() &&
		f.EndTime.IsZero() &&
		f.AccountID == "" &&
		f.Limit == 0 &&
		f.Offset == 0
}

// ValidStatus checks if a status string is a valid approval status.
func ValidStatus(status string) bool {
	switch status {
	case StatusPending, StatusApproved, StatusExpired, StatusRevoked:
		return true
	default:
		return false
	}
}

// ValidCloudType checks if a cloud type string is a valid cloud platform type.
func ValidCloudType(cloudType string) bool {
	switch cloudType {
	case CloudTypeAWS, CloudTypeGCP, CloudTypeAzure, CloudTypeAlibaba:
		return true
	default:
		return false
	}
}

// NewApprovalInstance creates a new ApprovalInstance with default values.
// The CreatedAt and UpdatedAt fields are set to the current time.
func NewApprovalInstance(id, email, accountID, cloudType string, permissionSets []string, startTime, endTime time.Time) *ApprovalInstance {
	now := time.Now()
	return &ApprovalInstance{
		ID:             id,
		Email:          email,
		AccountID:      accountID,
		PermissionSets: permissionSets,
		StartTime:      startTime,
		EndTime:        endTime,
		Status:         StatusPending,
		CloudType:      cloudType,
		CreatedAt:      now,
		UpdatedAt:      now,
	}
}

// NewPendingRemoval creates a new PendingRemoval with default values.
// The CreatedAt field is set to the current time.
func NewPendingRemoval(accountID, email, permissionSet, cloudType string, expiredAt, scheduledAt time.Time) *PendingRemoval {
	return &PendingRemoval{
		AccountID:     accountID,
		Email:         email,
		PermissionSet: permissionSet,
		CloudType:     cloudType,
		ExpiredAt:     expiredAt,
		ScheduledAt:   scheduledAt,
		CreatedAt:     time.Now(),
	}
}
