package market

import "testing"

func TestUniverseSelectorVocabulary(t *testing.T) {
	cases := []struct {
		kind UniverseSelectorKind
		want string
	}{
		{UniverseSelectorWatchlist, "watchlist"},
		{UniverseSelectorExchange, "exchange"},
		{UniverseSelectorSector, "sector"},
	}
	for _, c := range cases {
		if string(c.kind) != c.want {
			t.Errorf("selector kind %q: got %q, want %q", c.want, string(c.kind), c.want)
		}
	}

	if string(ProviderKIS) != "kis" {
		t.Errorf("ProviderKIS: got %q, want %q", string(ProviderKIS), "kis")
	}
}

func TestUniverseSelectorFields(t *testing.T) {
	sel := UniverseSelector{
		Kind:    UniverseSelectorExchange,
		Market:  MarketKR,
		Venue:   VenueKRX,
		Symbols: []string{"005930", "000660"},
		Name:    "semiconductors",
	}

	if sel.Kind != UniverseSelectorExchange {
		t.Errorf("Kind mismatch: got %v", sel.Kind)
	}
	if sel.Market != MarketKR || sel.Venue != VenueKRX {
		t.Errorf("market/venue mismatch: got %v/%v", sel.Market, sel.Venue)
	}
	if len(sel.Symbols) != 2 {
		t.Errorf("Symbols length: got %d, want 2", len(sel.Symbols))
	}
}

func TestMarketVenueMetadata(t *testing.T) {
	cases := []struct {
		venue        Venue
		wantOk       bool
		wantMarket   Market
		wantCurrency Currency
		wantTimezone string
	}{
		{VenueKRX, true, MarketKR, CurrencyKRW, "Asia/Seoul"},
		{VenueNASDAQ, true, MarketUS, CurrencyUSD, "America/New_York"},
		{VenueNYSE, true, MarketUS, CurrencyUSD, "America/New_York"},
		{Venue("UNKNOWN"), false, Market(""), Currency(""), ""},
	}
	for _, c := range cases {
		meta, ok := GetVenueMetadata(c.venue)
		if ok != c.wantOk {
			t.Errorf("GetVenueMetadata(%q) ok: got %v, want %v", c.venue, ok, c.wantOk)
		}
		if ok {
			if meta.Market != c.wantMarket || meta.Currency != c.wantCurrency || meta.Timezone != c.wantTimezone {
				t.Errorf("GetVenueMetadata(%q) meta mismatch: got %+v, want Market: %v, Currency: %v, Timezone: %v", c.venue, meta, c.wantMarket, c.wantCurrency, c.wantTimezone)
			}
		}
	}
}

func TestProviderCapabilityRequireDailyBars(t *testing.T) {
	// A KIS-like capability serving both KR and US daily bars.
	kis := ProviderCapability{
		Provider: ProviderKIS,
		Venues: map[Venue]bool{
			VenueKRX:    true,
			VenueNASDAQ: true,
			VenueNYSE:   true,
		},
		Timeframes: map[Timeframe]bool{TimeframeDaily: true},
	}
	// A narrower KR-only provider that must reject US venues.
	krOnly := ProviderCapability{
		Provider:   Provider("kiwoom"),
		Venues:     map[Venue]bool{VenueKRX: true},
		Timeframes: map[Timeframe]bool{TimeframeDaily: true},
	}

	sel := func(market Market, venue Venue) UniverseSelector {
		return UniverseSelector{Kind: UniverseSelectorWatchlist, Market: market, Venue: venue, Symbols: []string{"X"}}
	}

	cases := []struct {
		name     string
		cap      ProviderCapability
		provider Provider
		selector UniverseSelector
		wantErr  bool
	}{
		{"kis allows KR/KRX", kis, ProviderKIS, sel(MarketKR, VenueKRX), false},
		{"kis allows US/NASDAQ", kis, ProviderKIS, sel(MarketUS, VenueNASDAQ), false},
		{"kis allows US/NYSE", kis, ProviderKIS, sel(MarketUS, VenueNYSE), false},
		{"provider mismatch rejected", kis, Provider("yahoo"), sel(MarketUS, VenueNASDAQ), true},
		{"missing venue rejected", kis, ProviderKIS, sel(MarketUS, ""), true},
		{"unknown venue rejected", kis, ProviderKIS, sel(MarketUS, Venue("LSE")), true},
		{"market/venue mismatch rejected", kis, ProviderKIS, sel(MarketKR, VenueNASDAQ), true},
		{"kr-only capability rejects US", krOnly, Provider("kiwoom"), sel(MarketUS, VenueNASDAQ), true},
		{"kr-only capability allows KR", krOnly, Provider("kiwoom"), sel(MarketKR, VenueKRX), false},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			err := c.cap.RequireDailyBars(c.provider, c.selector)
			if c.wantErr && err == nil {
				t.Errorf("expected error, got nil")
			}
			if !c.wantErr && err != nil {
				t.Errorf("expected no error, got %v", err)
			}
		})
	}
}

func TestAssetTypeVocabulary(t *testing.T) {
	if string(AssetTypeEquity) != "equity" {
		t.Errorf("AssetTypeEquity: got %q, want %q", string(AssetTypeEquity), "equity")
	}
	if string(AssetTypeETF) != "etf" {
		t.Errorf("AssetTypeETF: got %q, want %q", string(AssetTypeETF), "etf")
	}
}
