const { Asset } = require("../../models");
const { Op } = require("sequelize");
const { ValidationError, NotFoundError, ConflictError } = require("../../utils/errors");

class adminAssetService {
  async getAssets(query = {}) {
    const {
      q,
      type,
      status,
      tradingEnabled,
      allowWallet,
      page = 1,
      limit = 20,
    } = query;

    const p = Math.max(Number(page) || 1, 1);
    const l = Math.min(Math.max(Number(limit) || 20, 1), 200);
    const offset = (p - 1) * l;

    const where = {};

    if (type) where.type = type;
    if (status) where.status = status;

    if (tradingEnabled === "true") where.tradingEnabled = true;
    if (tradingEnabled === "false") where.tradingEnabled = false;

    if (q && String(q).trim()) {
      const s = String(q).trim();
      where[Op.or] = [
        { symbol: { [Op.like]: `%${s}%` } },
        { name: { [Op.like]: `%${s}%` } },
      ];
    }

    const { rows, count } = await Asset.findAndCountAll({
      where,
      order: [["created_at", "DESC"]],
      limit: l,
      offset,
    });

    return {
      count,
      page: p,
      limit: l,
      assets: rows.map((a) => ({
        id: a.id,
        symbol: a.symbol,
        name: a.name,
        type: a.type,
        exchange: a.exchange,
        industry: a.industry,
        description: a.description,
        logo: a.logo,
        decimals: a.decimals,
        tradingEnabled: a.tradingEnabled,
        walletEnabled: a.allowWallet,
        status: a.status,
        metadata: a.metadata,
        createdAt: a.created_at,
        updatedAt: a.updated_at,
      })),
    };
  }

  async getSpotAssets(query = {}) {
    const {
      q,
      status,
      tradingEnabled,
      walletEnabled,
      page = 1,
      limit = 20,
    } = query;

    const p = Math.max(Number(page) || 1, 1);
    const l = Math.min(Math.max(Number(limit) || 20, 1), 200);
    const offset = (p - 1) * l;

    const where = {};

    where.type = "crypto";
    if (status) where.status = status;

    if (tradingEnabled === "true") where.tradingEnabled = true;
    if (tradingEnabled === "false") where.tradingEnabled = false;

    if (walletEnabled === "true") where.allowWallet = true;
    if (walletEnabled === "false") where.allowWallet = false;

    if (q && String(q).trim()) {
      const s = String(q).trim();
      where[Op.or] = [
        { symbol: { [Op.like]: `%${s}%` } },
        { name: { [Op.like]: `%${s}%` } },
      ];
    }

    const { rows, count } = await Asset.findAndCountAll({
      where,
      order: [["created_at", "DESC"]],
      limit: l,
      offset,
    });

    return {
      count,
      page: p,
      limit: l,
      assets: rows.map((a) => ({
        id: a.id,
        symbol: a.symbol,
        name: a.name,
        type: a.type,
        exchange: a.exchange,
        industry: a.industry,
        logo: a.logo,
        decimals: a.decimals,
        tradingEnabled: a.tradingEnabled,
        walletEnabled: a.allowWallet,
        status: a.status,
        metadata: a.metadata,
        createdAt: a.created_at,
        updatedAt: a.updated_at,
      })),
    };
  }

  async getAssetById(assetId) {
    const asset = await Asset.findByPk(assetId);
    if (!asset) throw new NotFoundError("Asset not found");
    return { asset };
  }

  // service
  async createAsset(data = {}, file, adminId = null) {
    const payload = this._sanitizeAssetPayload(data, { isCreate: true });

    const existing = await Asset.findOne({ where: { symbol: payload.symbol } });
    if (existing) throw new ConflictError("Symbol already exists");

    // ✅ attach file if uploaded
    if (file) payload.logo = file;

    const asset = await Asset.create(payload);
    return asset;
  }

  async updateAsset(assetId, data = {}, file, adminId = null) {
    const asset = await Asset.findByPk(assetId);
    if (!asset) throw new NotFoundError("Asset not found");

    const payload = this._sanitizeAssetPayload(data, { isCreate: false });

    if (payload.symbol && payload.symbol !== asset.symbol) {
      const existing = await Asset.findOne({ where: { symbol: payload.symbol } });
      if (existing) throw new ConflictError("Symbol already exists");
    }

    // ✅ only update logo if a new file was uploaded
    if (file) payload.logo = file;

    await asset.update(payload);
    return asset;
  }

  async deleteAsset(assetId, adminId = null) {
    const asset = await Asset.findByPk(assetId);
    if (!asset) throw new NotFoundError("Asset not found");

    await asset.destroy();
    return { ok: true };
  }

  _sanitizeAssetPayload(data, { isCreate }) {
    const out = {};

    const symbol = data.symbol != null ? String(data.symbol).trim().toUpperCase() : null;
    const name = data.name != null ? String(data.name).trim() : null;
    const type = data.type != null ? String(data.type).trim().toLowerCase() : null;

    const allowedTypes = ["crypto", "fiat", "stock", "forex", "commodity"];
    const allowedStatuses = ["active", "inactive", "delisting"];

    if (isCreate) {
      if (!symbol) throw new ValidationError("symbol is required");
      if (!name) throw new ValidationError("name is required");
      if (!type) throw new ValidationError("type is required");
    }

    if (symbol) out.symbol = symbol;
    if (name) out.name = name;

    if (type) {
      if (!allowedTypes.includes(type)) {
        throw new ValidationError(`type must be one of: ${allowedTypes.join(", ")}`);
      }
      out.type = type;
    }

    if (data.exchange !== undefined) out.exchange = data.exchange ? String(data.exchange).trim() : null;
    if (data.industry !== undefined) out.industry = data.industry ? String(data.industry).trim() : null;
   
    if (data.description !== undefined) out.description = data.description ? String(data.description).trim() : null;

    if (data.decimals !== undefined) {
      const d = Number(data.decimals);
      if (!Number.isInteger(d) || d < 0 || d > 18) {
        throw new ValidationError("decimals must be an integer between 0 and 18");
      }
      out.decimals = d;
    }

    if (data.tradingEnabled !== undefined) {
      out.tradingEnabled =
        data.tradingEnabled === true ||
        data.tradingEnabled === "true" ||
        data.tradingEnabled === 1 ||
        data.tradingEnabled === "1";
    }

    if (data.walletEnabled !== undefined) {
      out.allowWallet =
        data.walletEnabled === true ||
        data.walletEnabled === "true" ||
        data.walletEnabled === 1 ||
        data.walletEnabled === "1";
    }

    if (data.status !== undefined) {
      const s = data.status ? String(data.status).trim().toLowerCase() : null;
      if (s && !allowedStatuses.includes(s)) {
        throw new ValidationError(`status must be one of: ${allowedStatuses.join(", ")}`);
      }
      out.status = s || "active";
    }

    if (data.metadata !== undefined) {
      // allow object OR JSON string
      if (data.metadata && typeof data.metadata === "string") {
        try {
          out.metadata = JSON.parse(data.metadata);
        } catch (e) {
          throw new ValidationError("metadata must be valid JSON");
        }
      } else if (data.metadata && typeof data.metadata === "object") {
        out.metadata = data.metadata;
      } else {
        out.metadata = {};
      }
    }

    return out;
  }
}

module.exports = new adminAssetService();