package models

import (
	"time"

	"github.com/google/uuid"
)

// ===== User Types =====

type UserRole string

const (
	RoleVisitor   UserRole = "visitor"
	RoleTicketing UserRole = "ticketing"
	RoleAdmin     UserRole = "admin_event"
	RoleSuperAdmin UserRole = "super_admin"
	RoleWaliKelas UserRole = "wali_kelas"
)

type User struct {
	ID                 string    `json:"id"`
	Email              string    `json:"email"`
	PasswordHash       *string   `json:"-" db:"password_hash"`
	FullName           string    `json:"full_name" db:"full_name"`
	Role               UserRole  `json:"role"`
	IsVerified         bool      `json:"is_verified" db:"is_verified"`
	EmailVerifiedAt    *time.Time `json:"email_verified_at,omitempty" db:"email_verified_at"`
	ClassID            *string   `json:"class_id,omitempty" db:"class_id"`
	OAuthProvider      *string   `json:"oauth_provider,omitempty" db:"oauth_provider"`
	OAuthProviderID    *string   `json:"oauth_provider_id,omitempty" db:"oauth_provider_id"`
	AvatarURL          *string   `json:"avatar_url,omitempty" db:"avatar_url"`
	PasswordResetToken *string   `json:"-" db:"password_reset_token"`
	PasswordResetExpires *time.Time `json:"-" db:"password_reset_expires"`
	CreatedAt          time.Time `json:"created_at" db:"created_at"`
	UpdatedAt          time.Time `json:"updated_at" db:"updated_at"`
}

type AuthPayload struct {
	UserID    string   `json:"userId"`
	Email     string   `json:"email"`
	FullName  string   `json:"fullName,omitempty"`
	Role      UserRole `json:"role"`
	ClassID   *string  `json:"classId,omitempty"`
	ClassName *string  `json:"className,omitempty"`
}

type AuthToken struct {
	AccessToken  string `json:"accessToken"`
	RefreshToken string `json:"refreshToken"`
	ExpiresIn    int    `json:"expiresIn"`
}

// ===== Event Types =====

type EventStatus string

const (
	EventDraft     EventStatus = "draft"
	EventPublished EventStatus = "published"
	EventActive    EventStatus = "active"
	EventPaused    EventStatus = "paused"
	EventClosed    EventStatus = "closed"
	EventCancelled EventStatus = "cancelled"
)

type Event struct {
	ID                     string      `json:"id"`
	OrganizerID            string      `json:"organizer_id" db:"organizer_id"`
	Name                   string      `json:"name"`
	Description            *string     `json:"description"`
	Venue                  string      `json:"venue"`
	EventDate              time.Time   `json:"event_date" db:"event_date"`
	SaleStart              time.Time   `json:"sale_start" db:"sale_start"`
	SaleEnd                time.Time   `json:"sale_end" db:"sale_end"`
	TotalCapacity          int         `json:"total_capacity" db:"total_capacity"`
	RemainingCapacity      int         `json:"remaining_capacity" db:"remaining_capacity"`
	Status                 EventStatus `json:"status"`
	WarMode                bool        `json:"war_mode" db:"war_mode"`
	ImageURL               *string     `json:"image_url,omitempty" db:"image_url"`
	QueueMaxTicketsPerPerson *int      `json:"queue_max_tickets_per_person,omitempty" db:"queue_max_tickets_per_person"`
	QueueSessionDuration   *int        `json:"queue_session_duration,omitempty" db:"queue_session_duration"`
	QueueMaxActiveSessions *int        `json:"queue_max_active_sessions,omitempty" db:"queue_max_active_sessions"`
	CreatedAt              time.Time   `json:"created_at" db:"created_at"`
	UpdatedAt              time.Time   `json:"updated_at" db:"updated_at"`
	// Joined fields
	OrganizerName *string `json:"organizer_name,omitempty" db:"organizer_name"`
}

type TicketClass struct {
	ID                string    `json:"id"`
	EventID           string    `json:"event_id" db:"event_id"`
	Name              string    `json:"name"`
	Description       *string   `json:"description"`
	Price             float64   `json:"price"`
	TotalCapacity     int       `json:"total_capacity" db:"total_capacity"`
	RemainingCapacity int       `json:"remaining_capacity" db:"remaining_capacity"`
	SaleWindowStart   time.Time `json:"sale_window_start" db:"sale_window_start"`
	SaleWindowEnd     time.Time `json:"sale_window_end" db:"sale_window_end"`
	SeatPlanImage     *string   `json:"seat_plan_image,omitempty" db:"seat_plan_image"`
	CreatedAt         time.Time `json:"created_at" db:"created_at"`
	UpdatedAt         time.Time `json:"updated_at" db:"updated_at"`
}

type EventImage struct {
	ID           string    `json:"id"`
	EventID      string    `json:"event_id" db:"event_id"`
	ImageURL     string    `json:"image_url" db:"image_url"`
	DisplayOrder int       `json:"display_order" db:"display_order"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
}

// ===== Queue Types =====

type QueueStatus string

const (
	QueueWaiting   QueueStatus = "waiting"
	QueueActive    QueueStatus = "active"
	QueueExpired   QueueStatus = "expired"
	QueueCompleted QueueStatus = "completed"
	QueueCancelled QueueStatus = "cancelled"
)

type QueueEntry struct {
	ID          string      `json:"id"`
	EventID     string      `json:"event_id" db:"event_id"`
	UserID      string      `json:"user_id" db:"user_id"`
	Position    int         `json:"position"`
	IPAddress   *string     `json:"ip_address,omitempty" db:"ip_address"`
	Status      QueueStatus `json:"status"`
	EnteredAt   time.Time   `json:"entered_at" db:"entered_at"`
	ActivatedAt *time.Time  `json:"activated_at,omitempty" db:"activated_at"`
	ExpiresAt   *time.Time  `json:"expires_at,omitempty" db:"expires_at"`
	CompletedAt *time.Time  `json:"completed_at,omitempty" db:"completed_at"`
}

// ===== Order Types =====

type OrderStatus string

const (
	OrderPending    OrderStatus = "pending"
	OrderProcessing OrderStatus = "processing"
	OrderCompleted  OrderStatus = "completed"
	OrderCancelled  OrderStatus = "cancelled"
	OrderExpired    OrderStatus = "expired"
)

type Order struct {
	ID             string      `json:"id"`
	EventID        string      `json:"event_id" db:"event_id"`
	TicketClassID  string      `json:"ticket_class_id" db:"ticket_class_id"`
	BuyerID        string      `json:"buyer_id" db:"buyer_id"`
	Quantity       int         `json:"quantity"`
	TotalAmount    float64     `json:"total_amount" db:"total_amount"`
	BuyerName      string      `json:"buyer_name" db:"buyer_name"`
	BuyerEmail     string      `json:"buyer_email" db:"buyer_email"`
	BuyerPhone     string      `json:"buyer_phone" db:"buyer_phone"`
	Status         OrderStatus `json:"status"`
	OrderLockID    *string     `json:"order_lock_id,omitempty" db:"order_lock_id"`
	PromoID        *string     `json:"promo_id,omitempty" db:"promo_id"`
	DomainPromoID  *string     `json:"domain_promo_id,omitempty" db:"domain_promo_id"`
	DiscountAmount *float64    `json:"discount_amount,omitempty" db:"discount_amount"`
	OriginalAmount *float64    `json:"original_amount,omitempty" db:"original_amount"`
	CreatedAt      time.Time   `json:"created_at" db:"created_at"`
	UpdatedAt      time.Time   `json:"updated_at" db:"updated_at"`
	// Joined fields
	EventName       *string `json:"event_name,omitempty" db:"event_name"`
	EventDate       *time.Time `json:"event_date,omitempty" db:"event_date"`
	Venue           *string `json:"venue,omitempty" db:"venue"`
	TicketClassName *string `json:"ticket_class_name,omitempty" db:"ticket_class_name"`
}

type OrderLock struct {
	ID             string    `json:"id"`
	EventID        string    `json:"event_id" db:"event_id"`
	TicketClassID  string    `json:"ticket_class_id" db:"ticket_class_id"`
	QuantityLocked int       `json:"quantity_locked" db:"quantity_locked"`
	UserID         string    `json:"user_id" db:"user_id"`
	LockedAt       time.Time `json:"locked_at" db:"locked_at"`
	ExpiresAt      time.Time `json:"expires_at" db:"expires_at"`
	Status         string    `json:"status"`
}

// ===== Payment Types =====

type PaymentStatus string

const (
	PaymentPending    PaymentStatus = "pending"
	PaymentProcessing PaymentStatus = "processing"
	PaymentCompleted  PaymentStatus = "completed"
	PaymentFailed     PaymentStatus = "failed"
	PaymentExpired    PaymentStatus = "expired"
	PaymentRefunded   PaymentStatus = "refunded"
)

type Payment struct {
	ID                  string        `json:"id"`
	OrderID             string        `json:"order_id" db:"order_id"`
	Amount              float64       `json:"amount"`
	Gateway             string        `json:"gateway"`
	GatewayTransactionID *string      `json:"gateway_transaction_id,omitempty" db:"gateway_transaction_id"`
	QRISCode            *string       `json:"qris_code,omitempty" db:"qris_code"`
	PaymentURL          *string       `json:"payment_url,omitempty" db:"payment_url"`
	SnapToken           *string       `json:"snap_token,omitempty" db:"snap_token"`
	ExpiresAt           *time.Time    `json:"expires_at,omitempty" db:"expires_at"`
	Status              PaymentStatus `json:"status"`
	WebhookData         *string       `json:"webhook_data,omitempty" db:"webhook_data"`
	CreatedAt           time.Time     `json:"created_at" db:"created_at"`
	UpdatedAt           time.Time     `json:"updated_at" db:"updated_at"`
}

// ===== Ticket Types =====

type TicketStatus string

const (
	TicketUnused TicketStatus = "unused"
	TicketUsed   TicketStatus = "used"
	TicketVoided TicketStatus = "voided"
)

type Ticket struct {
	ID              string       `json:"id"`
	OrderID         string       `json:"order_id" db:"order_id"`
	BookingCode     string       `json:"booking_code" db:"booking_code"`
	QRCode          string       `json:"qr_code" db:"qr_code"`
	TicketClassName string       `json:"ticket_class_name" db:"ticket_class_name"`
	BuyerName       string       `json:"buyer_name" db:"buyer_name"`
	BuyerEmail      string       `json:"buyer_email" db:"buyer_email"`
	EventName       string       `json:"event_name" db:"event_name"`
	EventDate       time.Time    `json:"event_date" db:"event_date"`
	Status          TicketStatus `json:"status"`
	UsedAt          *time.Time   `json:"used_at,omitempty" db:"used_at"`
	UsedBy          *string      `json:"used_by,omitempty" db:"used_by"`
	CreatedAt       time.Time    `json:"created_at" db:"created_at"`
}

// ===== Promo Types =====

type PromoType string

const (
	PromoPercentage PromoType = "percentage"
	PromoFixed      PromoType = "fixed"
	PromoFree       PromoType = "free"
)

type Promo struct {
	ID           string    `json:"id"`
	Code         string    `json:"code"`
	Name         string    `json:"name"`
	Description  *string   `json:"description"`
	PromoType    PromoType `json:"promo_type" db:"promo_type"`
	Value        float64   `json:"value"`
	MinPurchase  float64   `json:"min_purchase" db:"min_purchase"`
	MaxDiscount  *float64  `json:"max_discount,omitempty" db:"max_discount"`
	UsageLimit   *int      `json:"usage_limit,omitempty" db:"usage_limit"`
	UsageCount   int       `json:"usage_count" db:"usage_count"`
	PerUserLimit int       `json:"per_user_limit" db:"per_user_limit"`
	EventID      *string   `json:"event_id,omitempty" db:"event_id"`
	ValidFrom    time.Time `json:"valid_from" db:"valid_from"`
	ValidUntil   time.Time `json:"valid_until" db:"valid_until"`
	IsActive     bool      `json:"is_active" db:"is_active"`
	CreatedBy    string    `json:"created_by" db:"created_by"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
	UpdatedAt    time.Time `json:"updated_at" db:"updated_at"`
	// Joined
	EventName *string `json:"event_name,omitempty" db:"event_name"`
}

type DomainPromo struct {
	ID          string    `json:"id"`
	Domain      string    `json:"domain"`
	PromoType   PromoType `json:"promo_type" db:"promo_type"`
	Value       float64   `json:"value"`
	MaxDiscount *float64  `json:"max_discount,omitempty" db:"max_discount"`
	EventID     *string   `json:"event_id,omitempty" db:"event_id"`
	Description *string   `json:"description"`
	IsActive    bool      `json:"is_active" db:"is_active"`
	CreatedBy   string    `json:"created_by" db:"created_by"`
	CreatedAt   time.Time `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time `json:"updated_at" db:"updated_at"`
	// Joined
	EventName *string `json:"event_name,omitempty" db:"event_name"`
}

type PromoValidation struct {
	Valid          bool         `json:"valid"`
	Message        *string      `json:"message,omitempty"`
	Promo          *Promo       `json:"promo,omitempty"`
	DomainPromo    *DomainPromo `json:"domainPromo,omitempty"`
	DiscountAmount float64      `json:"discountAmount"`
	FinalAmount    float64      `json:"finalAmount"`
}

type PromoUsage struct {
	ID            string    `json:"id"`
	PromoID       *string   `json:"promo_id,omitempty" db:"promo_id"`
	DomainPromoID *string   `json:"domain_promo_id,omitempty" db:"domain_promo_id"`
	UserID        string    `json:"user_id" db:"user_id"`
	OrderID       string    `json:"order_id" db:"order_id"`
	DiscountAmount float64  `json:"discount_amount" db:"discount_amount"`
	CreatedAt     time.Time `json:"created_at" db:"created_at"`
}

// ===== School Types =====

type Class struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Description *string   `json:"description"`
	CreatedBy   string    `json:"created_by" db:"created_by"`
	CreatedAt   time.Time `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time `json:"updated_at" db:"updated_at"`
}

type EventClass struct {
	ID      string `json:"id"`
	EventID string `json:"event_id" db:"event_id"`
	ClassID string `json:"class_id" db:"class_id"`
}

type WaliKelasClass struct {
	ID          string `json:"id"`
	WaliKelasID string `json:"wali_kelas_id" db:"wali_kelas_id"`
	ClassID     string `json:"class_id" db:"class_id"`
}

type WaliKelasOrder struct {
	ID           string    `json:"id"`
	WaliKelasID  string    `json:"wali_kelas_id" db:"wali_kelas_id"`
	StudentID    string    `json:"student_id" db:"student_id"`
	EventID      string    `json:"event_id" db:"event_id"`
	TicketClassID string   `json:"ticket_class_id" db:"ticket_class_id"`
	OrderID      string    `json:"order_id" db:"order_id"`
	Quantity     int       `json:"quantity"`
	Notes        *string   `json:"notes"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
}

// ===== System Types =====

type Setting struct {
	ID           string    `json:"id"`
	SettingKey   string    `json:"setting_key" db:"setting_key"`
	SettingValue string    `json:"setting_value" db:"setting_value"`
	Description  *string   `json:"description"`
	UpdatedAt    time.Time `json:"updated_at" db:"updated_at"`
}

type SystemLog struct {
	ID           string    `json:"id"`
	LogType      string    `json:"log_type" db:"log_type"`
	UserID       *string   `json:"user_id,omitempty" db:"user_id"`
	Action       string    `json:"action"`
	ResourceType *string   `json:"resource_type,omitempty" db:"resource_type"`
	ResourceID   *string   `json:"resource_id,omitempty" db:"resource_id"`
	Status       *string   `json:"status"`
	Details      *string   `json:"details"`
	IPAddress    *string   `json:"ip_address,omitempty" db:"ip_address"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
}

// ===== Request/Response Types =====

type LoginRequest struct {
	Email       string  `json:"email" binding:"required"`
	Password    string  `json:"password" binding:"required"`
	LoginTarget *string `json:"loginTarget,omitempty"`
}

type RegisterRequest struct {
	Email    string `json:"email" binding:"required"`
	Password string `json:"password" binding:"required,min=8"`
	FullName string `json:"fullName" binding:"required"`
}

type CreateOrderLockRequest struct {
	EventID       string `json:"eventId" binding:"required"`
	TicketClassID string `json:"ticketClassId" binding:"required"`
	Quantity      int    `json:"quantity" binding:"required,min=1"`
}

type ConvertLockRequest struct {
	LockID         string  `json:"lockId" binding:"required"`
	BuyerName      string  `json:"buyerName" binding:"required"`
	BuyerEmail     string  `json:"buyerEmail" binding:"required"`
	BuyerPhone     string  `json:"buyerPhone" binding:"required"`
	PromoCode      *string `json:"promoCode,omitempty"`
	UseDomainPromo *bool   `json:"useDomainPromo,omitempty"`
}

type PromoValidateRequest struct {
	Code       string `json:"code" binding:"required"`
	EventID    string `json:"eventId" binding:"required"`
	Amount     float64 `json:"amount" binding:"required"`
}

type CreatePaymentRequest struct {
	OrderID string `json:"orderId" binding:"required"`
}

type PaymentWebhookPayload struct {
	OrderID           string `json:"order_id"`
	TransactionID     string `json:"transaction_id"`
	TransactionStatus string `json:"transaction_status"`
	FraudStatus       string `json:"fraud_status"`
	StatusCode        string `json:"status_code"`
	GrossAmount       string `json:"gross_amount"`
	SignatureKey      string `json:"signature_key"`
	TransactionTime   string `json:"transaction_time"`
	SettlementTime    string `json:"settlement_time"`
	ExpiryTime        string `json:"expiry_time"`
	PaymentType       string `json:"payment_type"`
}

type QueueEnterRequest struct {
	EventID string `json:"eventId" binding:"required"`
}

type QueueActivateRequest struct {
	EventID string `json:"eventId" binding:"required"`
}

// Pagination
type Pagination struct {
	Page  int `json:"page" form:"page"`
	Limit int `json:"limit" form:"limit"`
}

// Helper to generate UUID
func NewUUID() string {
	return uuid.New().String()
}
