package model

import (
	"errors"
	"fmt"
	"time"
)

type Dividend struct {
	Symbol       string
	CurrencyCode string
	Product      TradeProduct
	Value        float64
	PaymentDate  time.Time
	TaxAmount    float64
	TaxRate      float64
	NetValue     float64
}

type CloseEntry struct {
	Shares    int
	InPrice   float64
	OutPrice  float64
	GainPrice float64
	CloseTime time.Time
}

type ClosedPosition struct {
	Symbol       string
	CurrencyCode string
	Product      TradeProduct
	Closes       []CloseEntry // each close carries its own prices + share count
	OpenTime     time.Time
	RealizedGain float64
	TaxAmount    float64
	HoldingDays  int
}

type Position struct {
	CompanyID    int
	Symbol       string
	CurrencyCode string
	CurrencyID   int
	Weight       float64
	CostBasis    float64
	Shares       int
}

type TradeProduct int

const (
	StockTrade      TradeProduct = iota // 0
	OptionCallTrade                     // 1
	OptionPutTrade                      // 2
	CurrencyTrade                       // 3
	BondTrade
)

type TradeType int

const (
	BuyType      TradeType = iota // 0
	SellType                      // 1
	DividendType                  // 2
)

type AddTradeRequest struct {
	Symbol       string    `json:"symbol"`
	Shares       int       `json:"shares"`
	Product      int       `json:"product"`
	Type         int       `json:"type"` // was bool, now int
	Price        float64   `json:"price"`
	CurrencyCode string    `json:"currency_code"`
	Date         time.Time `json:"date"`

	// Dividend-specific fields (only populated when Type == 2)
	TaxAmount   float64   `json:"tax_amount,omitempty"`
	TaxRate     float64   `json:"tax_rate,omitempty"`
	NetValue    float64   `json:"net_value,omitempty"`
	PaymentDate time.Time `json:"payment_date,omitempty"`
}

type Trade struct {
	Symbol       string
	CurrencyCode string
	Shares       int
	Product      TradeProduct
	Type         TradeType
	Price        float64
	Date         time.Time
}

func (r *AddTradeRequest) Validate() error {
	if r.Symbol == "" {
		return errors.New("empty Symbol string")
	}
	if r.Shares <= 0 {
		return errors.New("shares must be a positive integer")
	}
	if r.Product < 0 || r.Product > 3 {
		return errors.New("product must be between 0 and 3")
	}
	if r.Price <= 0 {
		return errors.New("price must be a positive number")
	}
	if r.CurrencyCode == "" {
		return errors.New("currency is required")
	}
	if r.Date.IsZero() {
		return errors.New("date is required")
	}
	if r.Date.After(time.Now()) {
		return errors.New("date cannot be in the future")
	}
	return nil
}

func (r AddTradeRequest) ToDividend() (Dividend, error) {
	if TradeType(r.Type) != DividendType {
		return Dividend{}, fmt.Errorf("trade type is not a dividend")
	}
	return Dividend{
		Symbol:       r.Symbol,
		CurrencyCode: r.CurrencyCode,
		Product:      TradeProduct(r.Product),
		Value:        r.Price, // gross value
		PaymentDate:  r.PaymentDate,
		TaxAmount:    r.TaxAmount,
		TaxRate:      r.TaxRate,
		NetValue:     r.NetValue,
	}, nil
}

func (r AddTradeRequest) ToTrade() (Trade, error) {
	t := TradeType(r.Type)
	if t != BuyType && t != SellType {
		return Trade{}, fmt.Errorf("trade type is not buy or sell")
	}
	return Trade{
		Symbol:       r.Symbol,
		CurrencyCode: r.CurrencyCode,
		Shares:       r.Shares,
		Product:      TradeProduct(r.Product),
		Type:         t,
		Price:        r.Price,
		Date:         r.Date,
	}, nil
}

// for now trades and none stock position will not be supported.
type Portifolio struct {
	Positions []Position
	Trades    []Trade
	closed    []ClosedPosition
	Dividends []Dividend
}
