const { Asset, TradingPair } = require("../models");

const QUOTES = ["USDT", "USDC", "BTC", "ETH"];

// “Tiering” like real exchanges
const TIER_1 = ["BTC", "ETH", "BNB", "SOL", "XRP", "ADA", "DOGE", "TRX", "TON", "AVAX", "LINK", "DOT", "MATIC", "LTC", "BCH"];
const TIER_2 = ["ATOM", "NEAR", "FIL", "ICP", "APT", "ARB", "OP", "SUI", "INJ", "RUNE", "GRT", "AAVE", "UNI", "LDO", "MKR", "COMP", "SNX", "CRV", "DYDX"];
const TIER_3 = [
  "FTM", "ALGO", "HBAR", "EGLD", "ROSE", "KAVA", "ZIL", "ONE", "CELO", "XLM", "ETC", "NEO", "IOTA", "XTZ", "FLOW", "KSM", "GAS", "WAVES", "QTUM",
  "SAND", "MANA", "AXS", "GALA", "CHZ", "ENJ", "IMX", "APE",
  "PEPE", "SHIB", "BONK", "FLOKI", "WIF",
  "RNDR", "FET", "AGIX", "OCEAN", "TAO", "ARKM",
];

// Categories (for UI filters)
const CATEGORIES = {
  "Layer 1": ["BTC", "ETH", "BNB", "SOL", "ADA", "AVAX", "DOT", "TRX", "TON", "NEAR", "ICP", "APT", "SUI", "ETC", "EGLD", "ALGO", "HBAR", "XTZ", "IOTA", "FLOW", "KSM", "NEO"],
  "DeFi": ["AAVE", "UNI", "MKR", "COMP", "SNX", "CRV", "DYDX", "INJ", "RUNE", "LDO"],
  "Infra": ["LINK", "GRT", "FIL", "RNDR"],
  "Gaming": ["AXS", "SAND", "MANA", "GALA", "IMX", "ENJ", "APE"],
  "Meme": ["DOGE", "SHIB", "PEPE", "BONK", "FLOKI", "WIF"],
  "AI": ["FET", "AGIX", "OCEAN", "TAO", "ARKM", "RNDR"],
};

const RULES = {
  tickSizeByQuote: { USDT: 0.0001, USDC: 0.0001, BTC: 0.00000001, ETH: 0.00000001 },
  defaultStepSize: 0.0001,

  stepSizeByBase: {
    BTC: 0.000001,
    ETH: 0.00001,
    BNB: 0.001,
    SOL: 0.001,
    XRP: 1,
    DOGE: 1,
    SHIB: 1000,
    PEPE: 100000,
    BONK: 1000,
    WIF: 0.01,
  },

  minQtyByBase: {
    BTC: 0.00001,
    ETH: 0.0001,
    BNB: 0.01,
    SOL: 0.01,
    XRP: 5,
    DOGE: 10,
    SHIB: 100000,
    PEPE: 500000,
    BONK: 100000,
    WIF: 0.1,
  },
};

const FX_MAJORS = [
  ["EUR", "USD"],
  ["GBP", "USD"],
  ["USD", "JPY"],
  ["USD", "CHF"],
  ["AUD", "USD"],
  ["USD", "CAD"],
  ["NZD", "USD"],
];

const FX_MINORS = [
  ["EUR", "GBP"], ["EUR", "JPY"], ["EUR", "CHF"], ["EUR", "AUD"], ["EUR", "CAD"], ["EUR", "NZD"],
  ["GBP", "JPY"], ["GBP", "CHF"], ["GBP", "AUD"], ["GBP", "CAD"], ["GBP", "NZD"],
  ["AUD", "JPY"], ["AUD", "NZD"], ["AUD", "CAD"], ["AUD", "CHF"],
  ["NZD", "JPY"], ["NZD", "CAD"], ["NZD", "CHF"],
  ["CAD", "JPY"], ["CAD", "CHF"],
  ["CHF", "JPY"],
];

const FX_EXOTICS = [
  ["USD", "ZAR"], ["EUR", "ZAR"], ["GBP", "ZAR"],
  ["USD", "TRY"], ["EUR", "TRY"], ["GBP", "TRY"],
  ["USD", "MXN"], ["EUR", "MXN"],
  ["USD", "BRL"], ["USD", "ARS"],
  ["USD", "INR"], ["EUR", "INR"],
  ["USD", "NGN"], ["EUR", "NGN"], ["GBP", "NGN"],

  ["USD", "KES"], ["USD", "GHS"], ["USD", "UGX"], ["USD", "TZS"],
  ["USD", "XOF"], ["USD", "XAF"], ["USD", "EGP"],

  ["USD", "PLN"], ["EUR", "PLN"],
  ["USD", "HUF"], ["EUR", "HUF"],
  ["USD", "CZK"], ["EUR", "CZK"],
  ["USD", "RON"], ["EUR", "RON"],
  ["USD", "SEK"], ["EUR", "SEK"],
  ["USD", "NOK"], ["EUR", "NOK"],
  ["USD", "DKK"], ["EUR", "DKK"],
];

function isJPYPair(base, quote) {
  return base === "JPY" || quote === "JPY";
}

// Forex tick rules (simple + realistic)
function fxTickSize(base, quote) {
  // JPY pairs usually quote to 0.01
  if (isJPYPair(base, quote)) return 0.01;
  // most others 0.0001 (4dp pip)
  return 0.0001;
}

// If you want 5-digit pricing (fractional pips), use 0.00001 / 0.001 for JPY.
// But since your engine may not need fractional pips, keep it simple.
function fxPrecisions(base, quote) {
  if (isJPYPair(base, quote)) return { pricePrecision: 2, tickSize: 0.01 };
  return { pricePrecision: 4, tickSize: 0.0001 };
}

function decimals(n) {
  const s = String(n);
  return s.includes(".") ? s.split(".")[1].replace(/0+$/, "").length : 0;
}

class TradingPairService {
  
    async seedCryptoPairs() {
    const crypto = await Asset.findAll({ where: { type: "crypto" } });
    const bySymbol = new Map(crypto.map(a => [a.symbol, a])); // { BTC -> assetRow }
   

    const quotesExisting = QUOTES.filter(q => bySymbol.has(q));
    if (quotesExisting.length === 0) {
      throw new Error("No quote assets found. Add USDT/USDC/BTC/ETH to Assets table first.");
    }
    console.log(`Quotes available: ${quotesExisting.join(", ")}`);


    const categoryOf = (sym) => {
      for (const [cat, list] of Object.entries(CATEGORIES)) {
        if (list.includes(sym)) return cat;
      }
      return "Other";
    };

   

    const pickQuotesForBase = (base) => {
      if (TIER_1.includes(base)) return quotesExisting;
      if (TIER_2.includes(base)) return ["USDT", "USDC", "BTC"].filter(q => quotesExisting.includes(q));
      return ["USDT", "USDC"].filter(q => quotesExisting.includes(q));
    };

     

    const allBases = [...new Set([...TIER_1, ...TIER_2, ...TIER_3])]
      .filter(s => bySymbol.has(s))
      .filter(s => !quotesExisting.includes(s)); // optional
   
    const decimals = (n) => {
      const s = String(n);
      return s.includes(".") ? s.split(".")[1].replace(/0+$/, "").length : 0;
    };

   
    const pairs = [];

    for (const base of allBases) {
      const baseAsset = bySymbol.get(base);
      if (!baseAsset) continue;

      const quotes = pickQuotesForBase(base);
      
      for (const quote of quotes) {
        const quoteAsset = bySymbol.get(quote);
        
        if (!quoteAsset) continue;
        if (base === quote) continue;
        
        const tickSize = RULES.tickSizeByQuote[quote] ?? 0.0001;
       
        const stepSize = RULES.stepSizeByBase[base] ?? RULES.defaultQtyStep;
         console.log(`Base ${base} with id: ${baseAsset.id} will have quotes: ${quote} with id: ${quoteAsset.id} with tick size ${tickSize} with step size ${stepSize}`);
        const minQuantity = RULES.minQtyByBase[base] ?? stepSize;
        
        pairs.push({
          name: `${base}_${quote}`,
          symbol: `${base}/${quote}`,

          // ✅ BIGINT IDs (matches your DB)
          baseAsset: baseAsset.id,
          quoteAsset: quoteAsset.id,

          market: "spot",
          category: categoryOf(base),

          minQuantity,
          maxQuantity: 1_000_000_000,
          stepSize,                 // ✅ correct field name
          tickSize,

          pricePrecision: decimals(tickSize),
          quantityPrecision: decimals(stepSize),

          status: "active",
          tradingEnabled: true,
          isFeatured: false,
          sortOrder: 0,
        });
      }
    }

    const created = await TradingPair.bulkCreate(pairs, {
      ignoreDuplicates: true,
      validate: true,
    });

    return {
      generated: pairs.length,
      insertedMaybe: created.length,
      quotesExisting,
      basesExisting: allBases.length,
    };
  }

  async seedForexPairs() {
    // 1) load FX assets
    const fxAssets = await Asset.findAll({ where: { type: "fx" } });
    const bySymbol = new Map(fxAssets.map(a => [a.symbol, a]));

    // 2) build the pair list
    const pairsToCreate = [
      ...FX_MAJORS.map(p => ({ base: p[0], quote: p[1], category: "Major" })),
      ...FX_MINORS.map(p => ({ base: p[0], quote: p[1], category: "Minor" })),
      ...FX_EXOTICS.map(p => ({ base: p[0], quote: p[1], category: "Exotic" })),
    ];

    const rows = [];

    for (const { base, quote, category } of pairsToCreate) {
      const baseAsset = bySymbol.get(base);
      const quoteAsset = bySymbol.get(quote);

      // skip if your DB doesn't have those currencies
      if (!baseAsset || !quoteAsset) continue;

      const { pricePrecision, tickSize } = fxPrecisions(base, quote);

      // In FX, quantity could be "lots" or "units". We'll do a safe default:
      // - 0.01 minimum (micro-lot style)
      // - step 0.01
      const stepSize = 0.01;
      const minQuantity = 0.01;

      rows.push({
        name: `${base}_${quote}`,
        symbol: `${base}/${quote}`,
        baseAsset: baseAsset.id,     // ✅ BIGINT id
        quoteAsset: quoteAsset.id,   // ✅ BIGINT id
        market: "forex",
        category,

        minQuantity,
        maxQuantity: 1_000_000_000,
        stepSize,
        tickSize,

        pricePrecision,
        quantityPrecision: decimals(stepSize),

        minNotional: 10,

        status: "active",
        tradingEnabled: true,
        isFeatured: category === "Major",
        sortOrder: category === "Major" ? 10 : category === "Minor" ? 20 : 30,
      });
    }

    const created = await TradingPair.bulkCreate(rows, {
      ignoreDuplicates: true,
      validate: true,
    });

    return {
      market: "forex",
      generated: rows.length,
      insertedMaybe: created.length,
      assetsLoaded: fxAssets.length,
      availableSymbols: [...bySymbol.keys()],
    };
  }
}

module.exports = new TradingPairService();