"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.metadata = void 0;
const db_1 = require("@b/db");
const sequelize_1 = require("sequelize");
exports.metadata = {
    summary: "Get ICO Offerings by Status",
    description: "Retrieves ICO token offerings filtered by a given status and additional query parameters such as pagination, search, sort, blockchain, tokenType. If the status is 'COMPLETED', the endpoint returns offerings with statuses 'SUCCESS' and 'FAILED'.",
    operationId: "getIcoOfferingsByStatus",
    tags: ["ICO", "Offerings"],
    logModule: "ICO",
    logTitle: "Get ICO Offers",
    parameters: [
        {
            index: 1,
            name: "status",
            in: "query",
            description: "The offering status to filter by (e.g., ACTIVE, UPCOMING, COMPLETED). Use COMPLETED to fetch offerings with SUCCESS or FAILED status.",
            required: false,
            schema: { type: "string" },
        },
        {
            index: 2,
            name: "page",
            in: "query",
            description: "Page number for pagination.",
            required: false,
            schema: { type: "number" },
        },
        {
            index: 3,
            name: "limit",
            in: "query",
            description: "Number of items per page for pagination.",
            required: false,
            schema: { type: "number" },
        },
        {
            index: 4,
            name: "search",
            in: "query",
            description: "Search term to filter offerings by name or symbol.",
            required: false,
            schema: { type: "string" },
        },
        {
            index: 5,
            name: "sort",
            in: "query",
            description: "Sort option for offerings. Valid values: newest, oldest, raised-high, raised-low, target-high, target-low, ending-soon.",
            required: false,
            schema: { type: "string" },
        },
        {
            index: 6,
            name: "blockchain",
            in: "query",
            description: "Filter by blockchain. Accepts one or more values (e.g., Ethereum, Solana, Polygon, Binance Smart Chain).",
            required: false,
            schema: { type: "string" },
            style: "form",
            explode: true,
        },
        {
            index: 7,
            name: "tokenType",
            in: "query",
            description: "Filter by token type. Accepts one or more values (e.g., Utility, Security, Governance).",
            required: false,
            schema: { type: "string" },
            style: "form",
            explode: true,
        },
    ],
    responses: {
        200: {
            description: "ICO offerings retrieved successfully.",
            content: {
                "application/json": {
                    schema: {
                        type: "object",
                        properties: {
                            items: {
                                type: "array",
                                items: {
                                    type: "object",
                                    properties: {
                                        id: {
                                            type: "string",
                                            description: "Unique identifier for the offering",
                                        },
                                        name: {
                                            type: "string",
                                            description: "Name of the offering",
                                        },
                                        ticker: {
                                            type: "string",
                                            description: "Token ticker",
                                        },
                                        description: {
                                            type: "string",
                                            description: "Detailed description of the offering",
                                        },
                                        status: {
                                            type: "string",
                                            description: "Current status (ACTIVE, PENDING, etc.). For COMPLETED queries, the status may be SUCCESS or FAILED.",
                                        },
                                        tokenPrice: {
                                            type: "number",
                                            description: "Current token price",
                                        },
                                        targetAmount: {
                                            type: "number",
                                            description: "Total funding target",
                                        },
                                        participants: {
                                            type: "number",
                                            description: "Number of participants",
                                        },
                                        isPaused: {
                                            type: "boolean",
                                            description: "Flag if the offering is paused",
                                        },
                                        isFlagged: {
                                            type: "boolean",
                                            description: "Flag if the offering is flagged",
                                        },
                                        startDate: {
                                            type: "string",
                                            format: "date-time",
                                            description: "Start date of the offering",
                                        },
                                        endDate: {
                                            type: "string",
                                            format: "date-time",
                                            description: "End date of the offering",
                                        },
                                        currentPhase: {
                                            type: "object",
                                            description: "Information about the current phase",
                                            properties: {
                                                name: {
                                                    type: "string",
                                                    description: "Name of the current phase",
                                                },
                                                tokenPrice: {
                                                    type: "number",
                                                    description: "Token price in the current phase",
                                                },
                                                allocation: {
                                                    type: "number",
                                                    description: "Total allocation in the phase",
                                                },
                                                remaining: {
                                                    type: "number",
                                                    description: "Remaining tokens in the phase",
                                                },
                                                endsIn: {
                                                    type: "number",
                                                    description: "Days until the phase ends (calculated dynamically)",
                                                },
                                            },
                                        },
                                        nextPhase: {
                                            type: "object",
                                            description: "Information about the next phase",
                                            properties: {
                                                name: {
                                                    type: "string",
                                                    description: "Name of the next phase",
                                                },
                                                tokenPrice: {
                                                    type: "number",
                                                    description: "Token price in the next phase",
                                                },
                                                allocation: {
                                                    type: "number",
                                                    description: "Total allocation in the phase",
                                                },
                                                remaining: {
                                                    type: "number",
                                                    description: "Remaining tokens in the phase",
                                                },
                                                endsIn: {
                                                    type: "number",
                                                    description: "Days until the phase ends (using its full duration)",
                                                },
                                            },
                                        },
                                        phases: {
                                            type: "array",
                                            description: "List of all phases for the offering",
                                            items: {
                                                type: "object",
                                                properties: {
                                                    name: {
                                                        type: "string",
                                                        description: "Phase name",
                                                    },
                                                    tokenPrice: {
                                                        type: "number",
                                                        description: "Token price during the phase",
                                                    },
                                                    allocation: {
                                                        type: "number",
                                                        description: "Total allocation for the phase",
                                                    },
                                                    remaining: {
                                                        type: "number",
                                                        description: "Remaining tokens for the phase",
                                                    },
                                                    duration: {
                                                        type: "number",
                                                        description: "Duration in days for the phase",
                                                    },
                                                },
                                            },
                                        },
                                        tokenDetail: {
                                            type: "object",
                                            description: "Detailed token information",
                                        },
                                        teamMembers: {
                                            type: "array",
                                            description: "List of team members",
                                            items: { type: "object" },
                                        },
                                        roadmapItems: {
                                            type: "array",
                                            description: "List of roadmap items",
                                            items: { type: "object" },
                                        },
                                        currentRaised: {
                                            type: "number",
                                            description: "Sum of all transactions (price * amount) associated with this offering",
                                        },
                                    },
                                },
                            },
                            pagination: {
                                type: "object",
                                properties: {
                                    currentPage: { type: "number" },
                                    totalPages: { type: "number" },
                                    totalItems: { type: "number" },
                                },
                            },
                        },
                    },
                },
            },
        },
        500: { description: "Internal Server Error." },
    },
};
exports.default = async (data) => {
    try {
        const { ctx } = data || {};
        ctx === null || ctx === void 0 ? void 0 : ctx.step("Fetching get ico offers");
        const { query } = data || {};
        // Parse parameters with defaults
        const statusParam = (query === null || query === void 0 ? void 0 : query.status)
            ? query.status.toUpperCase()
            : "PENDING";
        const page = query.page ? parseInt(query.page) : 1;
        const limit = query.limit ? parseInt(query.limit) : 10;
        const offset = (page - 1) * limit;
        const sort = query.sort || "newest";
        // Build base where clause from status
        const whereClause = {};
        if (statusParam === "COMPLETED") {
            whereClause.status = { [sequelize_1.Op.in]: ["SUCCESS", "FAILED"] };
        }
        else {
            whereClause.status = statusParam;
        }
        // Apply search filter on name and symbol using LIKE
        if (query.search) {
            const searchTerm = query.search;
            whereClause[sequelize_1.Op.or] = [
                { name: { [sequelize_1.Op.like]: `%${searchTerm}%` } },
                { symbol: { [sequelize_1.Op.like]: `%${searchTerm}%` } },
            ];
        }
        // Prepare tokenDetail conditions for blockchain and tokenType filters
        const tokenDetailConditions = {};
        if (query.blockchain) {
            const blockchains = Array.isArray(query.blockchain)
                ? query.blockchain
                : [query.blockchain];
            tokenDetailConditions.blockchain = { [sequelize_1.Op.in]: blockchains };
        }
        if (query.tokenType) {
            const tokenTypes = Array.isArray(query.tokenType)
                ? query.tokenType
                : [query.tokenType];
            tokenDetailConditions.tokenType = { [sequelize_1.Op.in]: tokenTypes };
        }
        Object.keys(tokenDetailConditions).forEach((key) => {
            whereClause[`$tokenDetail.${key}$`] = tokenDetailConditions[key];
        });
        // Determine order based on sort option
        const order = [];
        switch (sort) {
            case "newest":
                order.push(["createdAt", "DESC"]);
                break;
            case "oldest":
                order.push(["createdAt", "ASC"]);
                break;
            case "target-high":
                order.push(["targetAmount", "DESC"]);
                break;
            case "target-low":
                order.push(["targetAmount", "ASC"]);
                break;
            case "ending-soon":
                order.push(["endDate", "ASC"]);
                break;
            default:
                order.push(["createdAt", "DESC"]);
        }
        // Fetch offerings with findAndCountAll for proper pagination
        const { count, rows } = await db_1.models.icoTokenOffering.findAndCountAll({
            where: whereClause,
            include: [
                { model: db_1.models.icoTokenOfferingPhase, as: "phases" },
                {
                    model: db_1.models.icoTokenDetail,
                    as: "tokenDetail",
                    required: Object.keys(tokenDetailConditions).length > 0,
                },
                { model: db_1.models.icoTeamMember, as: "teamMembers" },
                { model: db_1.models.icoRoadmapItem, as: "roadmapItems" },
            ],
            limit,
            offset,
            order,
        });
        // Compute currentRaised for all offerings in one query
        const offeringIds = rows.map((offering) => offering.id);
        const raisedResults = await db_1.models.icoTransaction.findAll({
            attributes: [
                "offeringId",
                [(0, sequelize_1.fn)("SUM", (0, sequelize_1.literal)("price * amount")), "currentRaised"],
            ],
            where: {
                offeringId: { [sequelize_1.Op.in]: offeringIds },
                status: {
                    [sequelize_1.Op.not]: ["REJECTED"],
                },
            },
            group: ["offeringId"],
        });
        const raisedMap = {};
        raisedResults.forEach((result) => {
            const offeringId = result.get("offeringId");
            const sum = result.get("currentRaised");
            raisedMap[offeringId] = sum ? Number(sum) : 0;
        });
        // Transform offerings: compute currentPhase and nextPhase based on phases and date logic
        const now = new Date();
        const transformedOfferings = rows.map((offering) => {
            const phases = offering.phases || [];
            let cumulativeDays = 0;
            let currentPhase = null;
            let nextPhase = null;
            const startDate = new Date(offering.startDate);
            const daysSinceStart = Math.floor((now.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
            for (let i = 0; i < phases.length; i++) {
                cumulativeDays += phases[i].duration;
                if (daysSinceStart < cumulativeDays) {
                    const phaseEndsIn = cumulativeDays - daysSinceStart;
                    currentPhase = { ...phases[i].toJSON(), endsIn: phaseEndsIn };
                    if (i + 1 < phases.length) {
                        nextPhase = {
                            ...phases[i + 1].toJSON(),
                            endsIn: phases[i + 1].duration,
                        };
                    }
                    break;
                }
            }
            return {
                id: offering.id,
                name: offering.name,
                icon: offering.icon,
                purchaseWalletCurrency: offering.purchaseWalletCurrency,
                purchaseWalletType: offering.purchaseWalletType,
                symbol: offering.symbol,
                status: offering.status,
                tokenPrice: offering.tokenPrice,
                targetAmount: offering.targetAmount,
                participants: offering.participants,
                isPaused: offering.isPaused,
                isFlagged: offering.isFlagged,
                startDate: offering.startDate,
                endDate: offering.endDate,
                currentPhase,
                nextPhase,
                phases: phases.map((phase) => phase.toJSON()),
                tokenDetail: offering.tokenDetail
                    ? offering.tokenDetail.toJSON()
                    : null,
                teamMembers: offering.teamMembers
                    ? offering.teamMembers.map((tm) => tm.toJSON())
                    : [],
                roadmapItems: offering.roadmapItems
                    ? offering.roadmapItems.map((rm) => rm.toJSON())
                    : [],
                currentRaised: raisedMap[offering.id] || 0,
            };
        });
        ctx === null || ctx === void 0 ? void 0 : ctx.success("Get ICO Offers retrieved successfully");
        return {
            items: transformedOfferings,
            pagination: {
                currentPage: page,
                totalPages: Math.ceil(count / limit),
                totalItems: count,
                total: count,
            },
        };
    }
    catch (error) {
        console.error("Error in getIcoOfferingsByStatus:", error);
        throw error;
    }
};
