package forms

import (
	"time"

	"github.com/gin-gonic/gin"
	"github.com/shopspring/decimal"
)

type UnitCostsInput struct {
	//optional
	CostID        string            `json:"cost_id"`
	CostTimeStamp int64             `json:"cost_time_stamp"`
	Unit          string            `json:"unit"`
	Cost          int               `json:"cost"`
	Labels        map[string]string `json:"labels"`
}

type UnitCosts struct {
	CostID        string            `json:"cost_id"`
	CostTimeStamp int64             `json:"cost_time_stamp"`
	Unit          string            `json:"unit"`
	Cost          int               `json:"cost"`
	Labels        map[string]string `json:"labels"`

	CostPrice       decimal.Decimal `json:"price"`
	RawPrice        decimal.Decimal `json:"raw_price"`
	PackageID       uint            `json:"package_id"`
	PackageVersion  uint            `json:"package_version"`
	BindedPackageID uint            `json:"binded_package_id"`
	ConsumedSource  string          `json:"consumed_source"`
	InvoiceID       int             `json:"invoice_id"`
}

type UnitCostSummary struct {
	Unit      string            `json:"unit"`
	Labels    map[string]string `json:"labels"`
	CostPrice decimal.Decimal   `json:"price"`
	RawPrice  decimal.Decimal   `json:"raw_price"`
}

type UnitInfo struct {
	UnitKey     string `json:"unit" validate:"min=1"`
	Description string `json:"description"`
	//optional
	Category string `json:"category"`
}

type UnitCount struct {
	Unit  string `json:"unit"`
	Count int    `json:"count"`
}

type LabelMultipleFactorPrice struct {
	MultipleFactorLabel     string `json:"multiple_factor_label,omitempty"`
	MultipleFactorThreshold int    `json:"multiple_factor_threshold,omitempty"`
}

type UnitPrice struct {
	Unit  string          `json:"unit"`
	Price decimal.Decimal `json:"price"`
	LabelMultipleFactorPrice
}

type UnitPrices map[string]UnitPrice

type PackageInfoInput struct {
	UnitPrices           UnitPrices        `json:"unit_prices"`
	Discount             decimal.Decimal   `json:"discount"`
	Credits              decimal.Decimal   `json:"credits"`
	Labels               map[string]string `json:"labels"`
	Description          string            `json:"description"`
	CreditsEnable        bool              `json:"credits_enable"`
	CreditsOnly          bool              `json:"credits_only"`
	TenantMaxBindedTimes uint              `json:"tenant_max_binded_times"`
	ExpressionLabels     []ExpressionLabel `json:"expression_labels"`
	ExtraPricingInfos    []PricingInfo     `json:"extra_pricing_infos"`
}

type ExpressionLabel struct {
	Label    string `json:"label"`
	Operator string `json:"operator"`
	Value    string `json:"value"`
}

type PricingInfo struct {
	UnitPrices       UnitPrices        `json:"unit_prices"`
	Discount         *decimal.Decimal  `json:"discount"`
	Labels           map[string]string `json:"labels"`
	ExpressionLabels []ExpressionLabel `json:"expression_labels"`
}

type PackageInfo struct {
	PackageID  uint       `json:"package_id"`
	UnitPrices UnitPrices `json:"unit_prices"`
	// no need unit count for now, only pay for need
	// UnitCount   []UnitCount
	Discount             decimal.Decimal   `json:"discount"`
	Credits              decimal.Decimal   `json:"credits"`
	Labels               map[string]string `json:"labels"`
	ExpressionLabels     []ExpressionLabel `json:"expression_labels"`
	Description          string            `json:"description"`
	Version              uint              `json:"version"`
	CreditsEnable        bool              `json:"credits_enable"`
	CreditsOnly          bool              `json:"credits_only"`
	TenantMaxBindedTimes uint              `json:"tenant_max_binded_times"`
	ExtraPricingInfos    []PricingInfo     `json:"extra_pricing_infos"`
}

type BindedPackageInfoInput struct {
	PackageID uint `json:"package_id"`
}

type BindedPackageInfo struct {
	BindedPackageID        uint             `json:"binded_package_id"`
	TenantID               uint             `json:"tenant_id"`
	PackageID              uint             `json:"package_id"`
	BindedDiscount         *decimal.Decimal `json:"binded_discount"`
	BindedDiscountRecordID *uint            `json:"-"`
	RemainingCredits       decimal.Decimal  `json:"remaining_credits"`
	Status                 string           `json:"status"`
	PackageInfo            *PackageInfo     `json:"package_info"`
}

type CreditsChargeInfoInput struct {
	ChargeCount     decimal.Decimal `json:"charge_count"`
	ChargerTenantID uint            `json:"charger_tenant_id"`
	ChargerUserID   uint            `json:"charger_user_id"`
	ChargeReason    string          `json:"charge_reason"`
}

type CreditsChargeInfoMigrateInput struct {
	ChargeCount     decimal.Decimal `json:"charge_count"`
	ChargerTenantID uint            `json:"charger_tenant_id"`
	ChargerUserID   uint            `json:"charger_user_id"`
	ChargeReason    string          `json:"charge_reason"`
	ChargeTime      time.Time       `json:"charge_time"`
}

type ChangeBindedDiscountInput struct {
	BindedDiscount  *decimal.Decimal `json:"binded_discount"`
	ChangerTenantID uint             `json:"changer_tenant_id"`
	ChangerUserID   uint             `json:"changer_user_id"`
	ChangeReason    string           `json:"change_reason"`
}

type CreditsChargeInfo struct {
	BindedPackageID uint            `json:"binded_package_id"`
	ChargeCount     decimal.Decimal `json:"charge_count"`
	ChargerTenantID uint            `json:"charger_tenant_id"`
	ChargerUserID   uint            `json:"charger_user_id"`
	ChargeReason    string          `json:"charge_reason"`
	ChargeTime      time.Time       `json:"charge_time"`
}

type CreditsChargeHistory struct {
	BindedPackageID uint                `json:"binded_package_id"`
	History         []CreditsChargeInfo `json:"history"`
	TotalAmounts    decimal.Decimal     `json:"total_amounts"`
}

type PaymentMethodInput struct {
	PaymentType string `json:"payment_type"`
}

type PaymentMethod struct {
	TenantID        uint   `json:"tenant_id"`
	PaymentMethodID uint   `json:"payment_method_id"`
	PaymentType     string `json:"payment_type"`
	PaymentCode     string `json:"payment_code"`
	Payable         bool   `json:"payable"`
}

type CreateInvoiceReq struct {
	StartDate time.Time `json:"start_date"`
	Type      string    `json:"type"`
}

type Tenant struct {
	TenantID                  uint   `json:"tenant_id"`
	Name                      string `json:"name"`
	Email                     string `json:"email"`
	Plan                      string `json:"plan"`
	ThirdPartyAccountProvider string `json:"third_party_account_provider"`
	ThirdPartyAccountCode     string `json:"third_party_account_code"`
}

type CostExplorerQuery struct {
	StartDate time.Time `json:"start_date"`
	EndDate   time.Time `json:"end_date"`
	InvoiceID uint      `json:"invoice_id"`

	// Labels map[string]string `json:"labels"`
}

type Price struct {
	CostPrice decimal.Decimal `json:"cost_price"`
	RawPrice  decimal.Decimal `json:"raw_price"`
}

type LabelCosts map[string]CategoryCosts

type CategoryCosts struct {
	Price
	UnitsCosts         []UnitCosts      `json:"unit_costs,omitempty"`
	CategoryUnitsCosts map[string]Price `json:"category_unit_costs"`
}

type Costs struct {
	CategoryCosts
	LabelsUnitsCosts map[string]LabelCosts `json:"label_unit_costs"`
}

type Invoice struct {
	Costs
	InvoiceID uint      `json:"invoice_id"`
	TenantID  uint      `json:"tenant_id"`
	Status    string    `json:"status"`
	Type      string    `json:"type"`
	StartDate time.Time `json:"start_date"`
	EndDate   time.Time `json:"end_date"`
}

type CostExplorerResult struct {
	BindedInvoiceCosts   Costs `json:"binded_invoice_costs"`
	UnbindedInvoiceCosts Costs `json:"unbind_invoice_costs"`
	InvoiceCostsCosts    Costs `json:"invoice_costs"`
	CreditsCosts         Costs `json:"credits_costs"`
}

type MonthlycostExplorerResult struct {
	CostExplorerResult
	InvoiceGenerated bool `json:"invoice_generated"`
}

type CommitmentInvoiceInput struct {
	Amount decimal.Decimal `json:"amount"`
	Owner  string          `json:"owner"`
	Date   time.Time       `json:"time"`
}

type OKType struct {
	Status string `json:"status" example:"ok"`
}

var OK = gin.H{
	"status": "success",
}

type SubscriptionInput struct {
	FilePath      string `json:"file_path"`
	ContractEmail string `json:"contract_email"`
}

type Subscription struct {
	SubscriptionID uint       `json:"subscription_id"`
	TenantID       uint       `json:"tenant_id"`
	Status         string     `json:"status"`
	FilePath       string     `json:"file_path"`
	ContractEmail  string     `json:"contract_email"`
	AcceptedUser   *string    `json:"accepted_user"`
	AcceptedDate   *time.Time `json:"accepted_date"`
	RejectedUser   *string    `json:"rejected_user"`
	RejectedDate   *time.Time `json:"rejected_date"`
}

type SubscriptionChange struct {
	ChangeUser string `json:"change_user"`
}
