"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.metadata = void 0;
const db_1 = require("@b/db");
const sequelize_1 = require("sequelize");
const console_1 = require("@b/utils/console");
const error_1 = require("@b/utils/error");
exports.metadata = {
    summary: "Get ICO Offering by ID",
    description: "Retrieves detailed ICO token offering data by its unique identifier. The response includes related phases, token details, team members, and roadmap items. Additionally, it calculates the current and next phases based on the offering's start date and the durations of its phases.",
    operationId: "getIcoOfferingById",
    tags: ["ICO", "Offerings"],
    logModule: "ICO",
    logTitle: "Get ICO Offer",
    parameters: [
        {
            name: "id",
            in: "path",
            description: "Unique identifier of the ICO offering",
            required: true,
            schema: { type: "string" },
        },
    ],
    responses: {
        200: {
            description: "ICO offering retrieved successfully.",
            content: {
                "application/json": {
                    schema: {
                        type: "object",
                        properties: {
                            id: {
                                type: "string",
                                description: "Unique identifier for the offering",
                            },
                            name: { type: "string", description: "Name of the offering" },
                            symbol: { type: "string", description: "Token ticker" },
                            icon: { type: "string", description: "Offering icon URL" },
                            purchaseWalletCurrency: {
                                type: "string",
                                description: "Wallet currency for purchase",
                            },
                            purchaseWalletType: {
                                type: "string",
                                description: "Wallet type for purchase",
                            },
                            status: {
                                type: "string",
                                description: "Current status (ACTIVE, PENDING, etc.). For COMPLETED queries, the status may be SUCCESS or FAILED.",
                            },
                            tokenPrice: {
                                type: "number",
                                description: "Current active phase token price (used for purchase calculations)",
                            },
                            baseTokenPrice: {
                                type: "number",
                                description: "Base token price from offering (for reference)",
                            },
                            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",
                            },
                            nextPhase: {
                                type: "object",
                                description: "Information about the next phase",
                            },
                            phases: {
                                type: "array",
                                description: "List of all phases for the offering",
                                items: { type: "object" },
                            },
                            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",
                            },
                        },
                    },
                },
            },
        },
        404: { description: "ICO offering not found." },
        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 offer");
        // Validate input early
        const { id } = data.params || {};
        if (!id) {
            throw (0, error_1.createError)({ statusCode: 400, message: "No offering ID provided" });
        }
        // Fetch the offering with associations.
        // If phases need to be in a specific order, update the order option accordingly.
        const offering = await db_1.models.icoTokenOffering.findOne({
            where: { id },
            include: [
                {
                    model: db_1.models.icoTokenOfferingPhase,
                    as: "phases",
                    // Ensure phases are ordered properly (e.g., by a sortOrder or createdAt column)
                    order: [["sortOrder", "ASC"]],
                },
                {
                    model: db_1.models.icoTokenDetail,
                    as: "tokenDetail",
                    include: [{ model: db_1.models.icoTokenType, as: "tokenTypeData" }]
                },
                { model: db_1.models.icoTeamMember, as: "teamMembers" },
                { model: db_1.models.icoRoadmapItem, as: "roadmapItems" },
            ],
        });
        if (!offering) {
            ctx === null || ctx === void 0 ? void 0 : ctx.success("Get ICO Offer retrieved successfully");
            return { error: "Offering not found" };
        }
        // Kick off the aggregation query concurrently
        const currentRaisedPromise = db_1.models.icoTransaction.findOne({
            attributes: [[(0, sequelize_1.fn)("SUM", (0, sequelize_1.literal)("price * amount")), "currentRaised"]],
            where: {
                offeringId: id,
                status: { [sequelize_1.Op.not]: ["REJECTED"] },
            },
            raw: true,
        });
        // Calculate currentPhase and nextPhase based on the phases array
        const phases = offering.phases || [];
        const startDate = new Date(offering.startDate);
        const daysSinceStart = Math.floor((Date.now() - startDate.getTime()) / (1000 * 60 * 60 * 24));
        let cumulativeDays = 0;
        let currentPhase = null;
        let nextPhase = null;
        // First, try to find the active phase based on remaining tokens (matching purchase logic)
        const activePhaseByRemaining = phases.find((phase) => phase.remaining > 0);
        // Then calculate based on time
        for (let i = 0; i < phases.length; i++) {
            cumulativeDays += phases[i].duration;
            if (daysSinceStart < cumulativeDays) {
                currentPhase = {
                    ...phases[i].toJSON(),
                    endsIn: cumulativeDays - daysSinceStart,
                };
                if (i + 1 < phases.length) {
                    nextPhase = {
                        ...phases[i + 1].toJSON(),
                        endsIn: phases[i + 1].duration,
                    };
                }
                break;
            }
        }
        // If we found an active phase by remaining tokens, use that instead
        // This ensures consistency with the purchase endpoint logic
        if (activePhaseByRemaining && (!currentPhase || activePhaseByRemaining.sequence < currentPhase.sequence)) {
            currentPhase = {
                ...activePhaseByRemaining.toJSON(),
                endsIn: (currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.endsIn) || 0,
            };
        }
        // Await the currentRaised aggregation query
        const currentRaisedResult = await currentRaisedPromise;
        const currentRaised = currentRaisedResult && currentRaisedResult.currentRaised
            ? Number(currentRaisedResult.currentRaised)
            : 0;
        // Assemble the response with plain objects
        // Use current phase token price if available, otherwise fall back to offering token price
        const currentTokenPrice = (currentPhase === null || currentPhase === void 0 ? void 0 : currentPhase.tokenPrice) || offering.tokenPrice;
        const transformedOffering = {
            id: offering.id,
            name: offering.name,
            symbol: offering.symbol,
            icon: offering.icon,
            purchaseWalletCurrency: offering.purchaseWalletCurrency,
            purchaseWalletType: offering.purchaseWalletType,
            status: offering.status,
            tokenPrice: currentTokenPrice, // Use current phase price for accurate calculations
            baseTokenPrice: offering.tokenPrice, // Keep original price for reference
            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,
        };
        return transformedOffering;
    }
    catch (error) {
        console_1.logger.error("ICO_OFFER", "Error retrieving ICO offering by ID", error);
        throw error;
    }
};
