package market

import (
	"fmt"
	"time"
)

type Market string

const (
	MarketKR Market = "KR"
	MarketUS Market = "US"
)

type Venue string

const (
	VenueKRX    Venue = "KRX"
	VenueNASDAQ Venue = "NASDAQ"
	VenueNYSE   Venue = "NYSE"
)

type Currency string

const (
	CurrencyKRW Currency = "KRW"
	CurrencyUSD Currency = "USD"
)

type Timeframe string

const (
	TimeframeDaily Timeframe = "1d"
	TimeframeMin1  Timeframe = "1m"
	TimeframeMin5  Timeframe = "5m"
)

type InstrumentID string

type AssetType string

const (
	AssetTypeEquity AssetType = "equity"
	AssetTypeETF    AssetType = "etf"
)

type VenueMetadata struct {
	Venue    Venue
	Market   Market
	Currency Currency
	Timezone string
}

func GetVenueMetadata(v Venue) (VenueMetadata, bool) {
	switch v {
	case VenueKRX:
		return VenueMetadata{
			Venue:    VenueKRX,
			Market:   MarketKR,
			Currency: CurrencyKRW,
			Timezone: "Asia/Seoul",
		}, true
	case VenueNASDAQ:
		return VenueMetadata{
			Venue:    VenueNASDAQ,
			Market:   MarketUS,
			Currency: CurrencyUSD,
			Timezone: "America/New_York",
		}, true
	case VenueNYSE:
		return VenueMetadata{
			Venue:    VenueNYSE,
			Market:   MarketUS,
			Currency: CurrencyUSD,
			Timezone: "America/New_York",
		}, true
	default:
		return VenueMetadata{}, false
	}
}

type Instrument struct {
	ID              InstrumentID
	Market          Market
	Venue           Venue
	Symbol          string
	Name            string
	Currency        Currency
	AssetType       AssetType
	ProviderSymbols map[string]string
}

type Provider string

const ProviderKIS Provider = "kis"

// ProviderCapability declares the venues and timeframes a market data provider
// can serve. It keeps provider distinct from market: one provider (KIS) can
// declare several venues across multiple markets, while a narrower future
// provider can declare KR-only coverage without changing the import boundary.
type ProviderCapability struct {
	Provider   Provider
	Venues     map[Venue]bool
	Timeframes map[Timeframe]bool
}

// SupportsDailyBars reports whether the capability covers daily bars for venue.
func (c ProviderCapability) SupportsDailyBars(venue Venue) bool {
	return c.Venues[venue] && c.Timeframes[TimeframeDaily]
}

// RequireDailyBars is the pre-import gate that rejects unsupported
// provider/market/venue combinations before any fetch. It validates that the
// request provider matches this capability, that the selector pins a venue this
// capability supports, that the selector market (when set) agrees with the
// venue's market, and that the capability covers daily bars for that venue.
func (c ProviderCapability) RequireDailyBars(provider Provider, selector UniverseSelector) error {
	if provider != c.Provider {
		return fmt.Errorf("provider %q does not match capability provider %q", provider, c.Provider)
	}
	if selector.Venue == "" {
		return fmt.Errorf("provider %q daily bar import requires a venue", provider)
	}
	meta, ok := GetVenueMetadata(selector.Venue)
	if !ok {
		return fmt.Errorf("provider %q does not support venue %q", provider, selector.Venue)
	}
	if selector.Market != "" && selector.Market != meta.Market {
		return fmt.Errorf("selector market %q does not match venue %q market %q", selector.Market, selector.Venue, meta.Market)
	}
	if !c.SupportsDailyBars(selector.Venue) {
		return fmt.Errorf("provider %q does not support daily bars for venue %q", provider, selector.Venue)
	}
	return nil
}

type UniverseSelectorKind string

const (
	UniverseSelectorWatchlist UniverseSelectorKind = "watchlist"
	UniverseSelectorExchange  UniverseSelectorKind = "exchange"
	UniverseSelectorSector    UniverseSelectorKind = "sector"
)

type UniverseSelector struct {
	Kind    UniverseSelectorKind
	Market  Market
	Venue   Venue
	Symbols []string
	Name    string
}

type Decimal struct {
	Value string
}

type Price struct {
	Currency Currency
	Amount   Decimal
}

type Quantity struct {
	Amount Decimal
}

type Bar struct {
	InstrumentID InstrumentID
	Timeframe    Timeframe
	Timestamp    time.Time
	Open         Price
	High         Price
	Low          Price
	Close        Price
	Volume       Quantity
}
