package dto_admin

// The admin finance manager's contract.
//
// Four screens read these:
//
//	Settlement Pending   consultations billed to a customer whose earning no
//	                     admin has reviewed yet
//	To Be Settled        reviewed and approved, waiting for the job
//	Settlement History   the batches the job wrote, one row per astrologer run
//	Settled History      the individual consultations those batches closed

//------------------------------------------------
// Filters
//------------------------------------------------

// SettlementListFilter is read off the query string, the way the other
// paginated lists in this API read their filters.
type SettlementListFilter struct {
	Page  int    `json:"page"`
	Limit int    `json:"limit"`
	Search string `json:"search"`

	// PENDING, TO_BE_SETTLED, SETTLED, ON_HOLD, REJECTED or ALL.
	SettlementStatus string `json:"settlement_status"`

	// CHAT, AUDIO, VIDEO or ALL.
	Medium string `json:"medium"`

	AstrologerID uint `json:"astrologer_id"`
	UserID       uint `json:"user_id"`

	// YYYY-MM-DD, inclusive. Filters on when the session happened.
	FromDate string `json:"from_date"`
	ToDate   string `json:"to_date"`

	// createdAt, astrologerEarning or grossAmount, with direction asc/desc.
	SortBy  string `json:"sort_by"`
	SortDir string `json:"sort_dir"`
}

//------------------------------------------------
// Consultation rows
//------------------------------------------------

// ConsultationSettlementItem is one row of the settlement lists. It carries
// the customer, the astrologer, the session and the money split, because the
// admin reviewing a payout should not have to open three screens to judge it.
type ConsultationSettlementItem struct {
	ConsultationID uint   `json:"consultation_id"`
	ConsultationNo string `json:"consultation_no"`

	UserID       uint   `json:"user_id"`
	UserName     string `json:"user_name"`
	UserMobile   string `json:"user_mobile"`

	AstrologerID   uint   `json:"astrologer_id"`
	AstrologerName string `json:"astrologer_name"`

	Medium    string `json:"medium"`
	Status    string `json:"status"`
	EndReason string `json:"end_reason"`

	Duration      string  `json:"duration"`
	BilledMinutes int     `json:"billed_minutes"`
	RatePerMinute float64 `json:"rate_per_minute"`

	GrossAmount        float64 `json:"gross_amount"`
	PlatformFeePercent float64 `json:"platform_fee_percent"`
	PlatformFeeAmount  float64 `json:"platform_fee_amount"`
	AstrologerEarning  float64 `json:"astrologer_earning"`

	SettlementStatus string `json:"settlement_status"`
	SettlementID     uint   `json:"settlement_id,omitempty"`
	SettlementNo     string `json:"settlement_no,omitempty"`
	SettledAt        string `json:"settled_at,omitempty"`

	// The customer's review of this astrologer, so the admin can see whether
	// the session went well before releasing the money. Empty when the
	// customer left none.
	ReviewRating float64 `json:"review_rating"`
	ReviewText   string  `json:"review_text"`

	AdminRemarks string `json:"admin_remarks,omitempty"`

	ConsultationDate string `json:"consultation_date"`
}

// ConsultationSettlementListResponse pairs the page with the totals for the
// whole filtered set, which is what the header cards on the screen show.
type ConsultationSettlementListResponse struct {
	Items []ConsultationSettlementItem `json:"items"`

	Page       int   `json:"page"`
	Limit      int   `json:"limit"`
	Total      int64 `json:"total"`
	TotalPages int   `json:"total_pages"`

	// Across every row the filter matches, not just this page.
	TotalGross     float64 `json:"total_gross"`
	TotalPlatformFee float64 `json:"total_platform_fee"`
	TotalEarning   float64 `json:"total_earning"`
}

//------------------------------------------------
// Detail
//------------------------------------------------

// ConsultationSettlementDetail is the review screen: the session, the money,
// the customer's review and every settlement transition the row has been
// through.
type ConsultationSettlementDetail struct {
	ConsultationSettlementItem

	ChannelName string `json:"channel_name,omitempty"`

	StartedAt string `json:"started_at,omitempty"`
	EndedAt   string `json:"ended_at,omitempty"`

	DurationSeconds int `json:"duration_seconds"`
	BilledSeconds   int `json:"billed_seconds"`

	// The cap the session was authorised for, and whether billing hit it.
	MaxBillableSeconds int  `json:"max_billable_seconds"`
	HitBalanceCap      bool `json:"hit_balance_cap"`

	// Consultee details, which are often not the account holder's.
	ConsulteeName  string `json:"consultee_name,omitempty"`
	ConsulteeBirth string `json:"consultee_birth_date,omitempty"`
	BirthTime      string `json:"consultee_birth_time,omitempty"`
	BirthPlace     string `json:"consultee_birth_place,omitempty"`
	Gender         string `json:"consultee_gender,omitempty"`

	AstrologerMobile string `json:"astrologer_mobile,omitempty"`
	UserEmail        string `json:"user_email,omitempty"`

	// The customer's wallet debit for this session, so the admin can confirm
	// the money actually left the wallet.
	WalletDebit float64 `json:"wallet_debit"`

	History []SettlementLogItem `json:"history"`
}

type SettlementLogItem struct {
	FromStatus string `json:"from_status"`
	ToStatus   string `json:"to_status"`
	Remarks    string `json:"remarks,omitempty"`

	ActionBy     uint   `json:"action_by"`
	ActionByName string `json:"action_by_name,omitempty"`
	ActionSource string `json:"action_source"`

	SettlementID uint   `json:"settlement_id,omitempty"`
	ActionAt     string `json:"action_at"`
}

//------------------------------------------------
// Review actions
//------------------------------------------------

// ReviewSettlementRequest is the admin's decision on one or many
// consultations. Bulk by design — the pending list is reviewed with
// checkboxes, and approving forty rows should be one call and one audit
// timestamp.
type ReviewSettlementRequest struct {
	ConsultationIDs []uint `json:"consultation_ids" binding:"required"`

	// APPROVE moves PENDING/ON_HOLD to TO_BE_SETTLED, HOLD parks a row,
	// REJECT refuses it for good, and REVERT sends a TO_BE_SETTLED row back
	// to PENDING as long as the job has not swept it yet.
	Action string `json:"action" binding:"required"`

	Remarks string `json:"remarks"`
}

type ReviewSettlementResponse struct {
	Action string `json:"action"`

	UpdatedCount int  `json:"updated_count"`
	UpdatedIDs   []uint `json:"updated_ids"`

	// Rows the action could not touch, each with the reason, so the panel can
	// tell the admin exactly what happened rather than failing the lot.
	Skipped []SkippedConsultation `json:"skipped"`

	TotalEarning float64 `json:"total_earning"`
}

type SkippedConsultation struct {
	ConsultationID uint   `json:"consultation_id"`
	Reason         string `json:"reason"`
}

//------------------------------------------------
// Settlement run
//------------------------------------------------

// RunSettlementRequest drives the job the admin panel's cron calls. Every
// field is optional: with an empty body it settles everything that is
// TO_BE_SETTLED.
type RunSettlementRequest struct {
	// Settle one astrologer only. 0 means all of them.
	AstrologerID uint `json:"astrologer_id"`

	// Only consultations that ended on or before this date, YYYY-MM-DD.
	// Lets a weekly run close a period cleanly even if it fires late.
	UpToDate string `json:"up_to_date"`

	// Report what would be settled and change nothing. The panel uses this
	// for the confirmation screen before a manual run.
	DryRun bool `json:"dry_run"`
}

// SettlementBatchResult is one astrologer's share of a run.
type SettlementBatchResult struct {
	AstrologerID   uint   `json:"astrologer_id"`
	AstrologerName string `json:"astrologer_name"`

	SettlementID uint   `json:"settlement_id,omitempty"`
	SettlementNo string `json:"settlement_no,omitempty"`

	ConsultationCount int     `json:"consultation_count"`
	GrossAmount       float64 `json:"gross_amount"`
	PlatformFee       float64 `json:"platform_fee"`
	SettledAmount     float64 `json:"settled_amount"`

	WalletBalanceAfter float64 `json:"wallet_balance_after"`

	PeriodFrom string `json:"period_from,omitempty"`
	PeriodTo   string `json:"period_to,omitempty"`

	// Set when this astrologer's batch was skipped — below
	// SettlementMinPayout, or a failure that must not stop the other
	// astrologers from settling.
	Skipped bool   `json:"skipped"`
	Reason  string `json:"reason,omitempty"`
}

type RunSettlementResponse struct {
	DryRun bool `json:"dry_run"`

	AstrologerCount   int     `json:"astrologer_count"`
	ConsultationCount int     `json:"consultation_count"`
	SettledAmount     float64 `json:"settled_amount"`

	Batches []SettlementBatchResult `json:"batches"`

	RunAt string `json:"run_at"`
}

//------------------------------------------------
// Settlement history (batches)
//------------------------------------------------

type SettlementBatchItem struct {
	SettlementID uint   `json:"settlement_id"`
	SettlementNo string `json:"settlement_no"`

	AstrologerID   uint   `json:"astrologer_id"`
	AstrologerName string `json:"astrologer_name"`

	ConsultationCount int     `json:"consultation_count"`
	GrossAmount       float64 `json:"gross_amount"`
	PlatformFee       float64 `json:"platform_fee"`
	Amount            float64 `json:"amount"`

	Status string `json:"status"`

	PeriodFrom string `json:"period_from,omitempty"`
	PeriodTo   string `json:"period_to,omitempty"`

	// Admin user id, or 0 when the scheduler ran it.
	ProcessedBy uint   `json:"processed_by"`
	ProcessedByName string `json:"processed_by_name,omitempty"`

	Remarks string `json:"remarks,omitempty"`

	SettlementDate string `json:"settlement_date,omitempty"`
	CreatedAt      string `json:"created_at"`
}

type SettlementBatchListResponse struct {
	Items []SettlementBatchItem `json:"items"`

	Page       int   `json:"page"`
	Limit      int   `json:"limit"`
	Total      int64 `json:"total"`
	TotalPages int   `json:"total_pages"`

	TotalAmount float64 `json:"total_amount"`
}

// SettlementBatchDetail opens one batch and lists the consultations it closed.
type SettlementBatchDetail struct {
	SettlementBatchItem

	Consultations []ConsultationSettlementItem `json:"consultations"`
}

//------------------------------------------------
// Finance summary
//------------------------------------------------

// FinanceSummaryResponse is the finance manager's header: what is waiting on a
// review, what the next run will pay out, and what has already gone out.
type FinanceSummaryResponse struct {
	PendingCount  int64   `json:"pending_count"`
	PendingAmount float64 `json:"pending_amount"`

	ToBeSettledCount  int64   `json:"to_be_settled_count"`
	ToBeSettledAmount float64 `json:"to_be_settled_amount"`

	OnHoldCount  int64   `json:"on_hold_count"`
	OnHoldAmount float64 `json:"on_hold_amount"`

	RejectedCount  int64   `json:"rejected_count"`
	RejectedAmount float64 `json:"rejected_amount"`

	SettledCount  int64   `json:"settled_count"`
	SettledAmount float64 `json:"settled_amount"`

	// Gross billed to customers and the platform's share of it, all time.
	TotalGrossBilled  float64 `json:"total_gross_billed"`
	TotalPlatformFee  float64 `json:"total_platform_fee"`

	// This calendar month, on the same basis.
	MonthGrossBilled float64 `json:"month_gross_billed"`
	MonthPlatformFee float64 `json:"month_platform_fee"`
	MonthSettled     float64 `json:"month_settled"`

	// Money credited to astrologer wallets that has not been withdrawn yet —
	// the platform's outstanding liability.
	AstrologerWalletBalance float64 `json:"astrologer_wallet_balance"`

	LastSettlementAt string `json:"last_settlement_at,omitempty"`
	NextSettlementAt string `json:"next_settlement_at,omitempty"`
}

//------------------------------------------------
// Stale session sweep
//------------------------------------------------

// SweepResponse reports what the stale-session sweep closed. The admin panel's
// cron calls the sweep on a short schedule; the settlement run is separate and
// slower.
// SweepResponse reports every pass of the consultation sweep separately, so a
// scheduler log says what actually happened rather than one opaque number.
type SweepResponse struct {
	// Sessions that were billed and closed: the cap and the stale passes
	// together. Kept as the first field because the panel's existing
	// scheduler reads it.
	ClosedCount int `json:"closed_count"`

	// Sessions where both parties were told the session is about to end.
	WarnedCount int `json:"warned_count"`

	// Closed because they reached their cap — the wallet ran out, or a free
	// chat used up its minutes.
	CappedCount int `json:"capped_count"`

	// Closed because the ticks stopped arriving.
	AbandonedCount int `json:"abandoned_count"`

	// Requests that rang out unanswered. Nothing billed.
	MissedCount int `json:"missed_count"`

	// Accepted, but the customer never opened the session, so the astrologer
	// was released. Nothing billed.
	UnjoinedCount int `json:"unjoined_count"`

	// Astrologers who were marked busy with no open session. This is the only
	// thing that can un-wedge one stuck busy by a crash.
	BusyReconciled int `json:"busy_reconciled"`

	// A pass that failed is recorded here and the rest still ran.
	Errors []string `json:"errors,omitempty"`

	RunAt string `json:"run_at"`
}
