/**
 * Wild Dragon MAM - Premiere Pro ExtendScript
 *
 * This file runs in the Premiere Pro host context (not the browser panel).
 * It is registered via <ScriptPath> in manifest.xml and called from the
 * panel via csInterface.evalScript().
 *
 * ExtendScript is ES3-level JavaScript — no arrow functions, no const/let,
 * no template literals, no destructuring.
 */

// ============================================================================
// Core Import Functions
// ============================================================================

/**
 * Imports a media file into the active Premiere Pro project.
 * @param {string} filePath - Full path to the file to import
 * @returns {string} JSON string with success status and message
 */
function importFileToProject(filePath) {
    var result = {
        success: false,
        message: "",
        itemID: null
    };

    try {
        if (!app.project) {
            result.message = "No active Premiere Pro project";
            return JSON.stringify(result);
        }

        var file = new File(filePath);
        if (!file.exists) {
            result.message = "File does not exist: " + filePath;
            return JSON.stringify(result);
        }

        app.project.importFiles([filePath]);

        result.success = true;
        result.message = "File imported successfully";
        return JSON.stringify(result);
    } catch (error) {
        result.message = "Error importing file: " + error.message;
        return JSON.stringify(result);
    }
}

/**
 * Gets the active sequence in the project.
 * @returns {string} JSON string with sequence name and ID, or nulls
 */
function getActiveSequence() {
    var result = {
        sequenceName: null,
        sequenceID: null
    };

    try {
        if (!app.project) return JSON.stringify(result);

        var activeSequence = app.project.activeSequence;
        if (activeSequence) {
            result.sequenceName = activeSequence.name;
            result.sequenceID   = activeSequence.sequenceID;
        }
        return JSON.stringify(result);
    } catch (error) {
        return JSON.stringify(result);
    }
}

/**
 * Inserts a clip into the active sequence at the playhead position.
 * @param {string} filePath   - Full path to the media file
 * @param {number} trackIndex - Video track index (1-based)
 * @returns {string} JSON string with success status
 */
function insertClipToSequence(filePath, trackIndex) {
    var result = {
        success: false,
        message: ""
    };

    try {
        if (!app.project) {
            result.message = "No active project";
            return JSON.stringify(result);
        }

        var sequence = app.project.activeSequence;
        if (!sequence) {
            result.message = "No active sequence";
            return JSON.stringify(result);
        }

        app.project.importFiles([filePath]);

        var file = new File(filePath);
        var fileName = file.displayName;
        var rootBin = app.project.rootItem;
        var projectItem = findProjectItemByName(rootBin, fileName);

        if (!projectItem) {
            result.message = "Could not find imported file in project";
            return JSON.stringify(result);
        }

        if (trackIndex < 1 || trackIndex > sequence.videoTracks.numTracks) {
            result.message = "Invalid track index: " + trackIndex;
            return JSON.stringify(result);
        }

        var track = sequence.videoTracks[trackIndex - 1];
        var playheadTime = sequence.getPlayerPosition();
        var trackItem = track.insertClip(projectItem, playheadTime);

        if (trackItem) {
            result.success = true;
            result.message = "Clip inserted at track " + trackIndex;
        } else {
            result.message = "Failed to insert clip into track";
        }

        return JSON.stringify(result);
    } catch (error) {
        result.message = "Error inserting clip: " + error.message;
        return JSON.stringify(result);
    }
}

/**
 * Gets the current project file path.
 * @returns {string} JSON string with project path and name
 */
function getProjectPath() {
    var result = {
        projectPath: null,
        projectName: null
    };

    try {
        if (!app.project) return JSON.stringify(result);

        result.projectPath = app.project.path;
        result.projectName = app.project.name;
        return JSON.stringify(result);
    } catch (error) {
        return JSON.stringify(result);
    }
}

/**
 * Gets information about all video tracks in the active sequence.
 * @returns {string} JSON string with an array of track objects
 */
function getSequenceTracks() {
    var result = { tracks: [] };

    try {
        if (!app.project) return JSON.stringify(result);

        var sequence = app.project.activeSequence;
        if (!sequence) return JSON.stringify(result);

        for (var i = 0; i < sequence.videoTracks.numTracks; i++) {
            var track = sequence.videoTracks[i];
            result.tracks.push({
                index: i + 1,
                name:  track.name || ("V" + (i + 1)),
                type:  "video"
            });
        }
        return JSON.stringify(result);
    } catch (error) {
        return JSON.stringify(result);
    }
}

/**
 * Gets the current playhead position in the active sequence.
 * @returns {string} JSON string with timeInSeconds and SMPTE timeCode
 */
function getPlayheadPosition() {
    var result = {
        timeInSeconds: 0,
        timeCode: ""
    };

    try {
        if (!app.project) return JSON.stringify(result);

        var sequence = app.project.activeSequence;
        if (!sequence) return JSON.stringify(result);

        var time   = sequence.getPlayerPosition();
        var ticks  = parseFloat(time.ticks);
        // Premiere Pro ticks: 254016000000 ticks per second
        var TICKS_PER_SECOND = 254016000000;
        var totalSeconds = ticks / TICKS_PER_SECOND;
        result.timeInSeconds = totalSeconds;

        // Build SMPTE timecode — use sequence frame rate
        var frameRate   = sequence.timebase ? (TICKS_PER_SECOND / parseFloat(sequence.timebase)) : 25;
        var totalFrames = Math.floor(totalSeconds * frameRate);
        var hours   = Math.floor(totalFrames / (frameRate * 3600));
        var minutes = Math.floor((totalFrames % (frameRate * 3600)) / (frameRate * 60));
        var seconds = Math.floor((totalFrames % (frameRate * 60))  / frameRate);
        var frames  = totalFrames % Math.round(frameRate);

        result.timeCode = pad(hours, 2) + ":" + pad(minutes, 2) + ":" +
                          pad(seconds, 2) + ":" + pad(frames, 2);
        return JSON.stringify(result);
    } catch (error) {
        return JSON.stringify(result);
    }
}

/**
 * Gets basic project information.
 * @returns {string} JSON string with project name, path, and sequence count
 */
function getProjectInfo() {
    var result = {
        projectName: "",
        projectPath: "",
        sequenceCount: 0
    };

    try {
        if (!app.project) return JSON.stringify(result);

        result.projectName = app.project.name;
        result.projectPath = app.project.path;

        var rootBin = app.project.rootItem;
        if (rootBin && rootBin.children) {
            for (var i = 0; i < rootBin.children.numItems; i++) {
                if (rootBin.children[i].type === ProjectItemType.SEQUENCE) {
                    result.sequenceCount++;
                }
            }
        }
        return JSON.stringify(result);
    } catch (error) {
        return JSON.stringify(result);
    }
}

/**
 * Exports the current sequence using Adobe Media Encoder.
 *
 * AME must be installed. This function launches AME (if not already running)
 * and queues the export job — it returns immediately; encoding happens in the
 * background and the output file appears when AME finishes.
 *
 * @param {string} outputPath  - Absolute path for the output file
 * @param {string} presetPath  - Absolute path to an AME preset file (.epr);
 *                               pass an empty string to use the sequence's
 *                               current export settings.
 * @returns {string} JSON string with success flag, message, and jobId
 */
function exportSequence(outputPath, presetPath) {
    var result = {
        success: false,
        message: "",
        jobId: null
    };

    try {
        if (!app.project) {
            result.message = "No active project";
            return JSON.stringify(result);
        }

        var sequence = app.project.activeSequence;
        if (!sequence) {
            result.message = "No active sequence";
            return JSON.stringify(result);
        }

        // Ensure Adobe Media Encoder is running before queuing
        app.encoder.launchEncoder();

        // encodeSequence(sequence, outputFilePath, presetPath, workAreaType, removeOnCompletion)
        // workAreaType: ENCODE_ENTIRE = 0, ENCODE_IN_TO_OUT = 1
        var jobId = app.encoder.encodeSequence(
            sequence,
            outputPath,
            presetPath || "",
            app.encoder.ENCODE_ENTIRE,
            false  // keep job in AME queue after completion
        );

        if (jobId) {
            result.success = true;
            result.message = "Export queued in Adobe Media Encoder";
            result.jobId   = jobId;
        } else {
            result.message = "AME returned no job ID — verify that the preset path is valid";
        }

        return JSON.stringify(result);
    } catch (error) {
        result.message = "Export error: " + error.message;
        return JSON.stringify(result);
    }
}

// ============================================================================
// Timeline Export — read sequence clips for MAM round-trip
// ============================================================================

/**
 * Reads all clips from all video tracks in the active sequence.
 * Returns JSON with sequence settings and a flat clip array.
 *
 * Each clip entry contains:
 *   filePath          – absolute OS path to source media (for MAM asset ID lookup)
 *   fileName          – project panel display name
 *   trackIndex        – 0-based video track index (0 = V1, 1 = V2, …)
 *   sourceInFrames    – in-point within source media, in frames
 *   sourceOutFrames   – out-point within source media, in frames
 *   timelineInFrames  – clip start position on timeline, in frames
 *   timelineOutFrames – clip end position on timeline, in frames
 *
 * sequence.timebase is ticks-per-frame.  Premiere uses 254,016,000,000
 * ticks/second, so fps = 254016000000 / timebase.
 */
function exportTimelineData() {
    var result = {
        success:      false,
        message:      "",
        sequenceName: "",
        frameRate:    59.94,
        width:        1920,
        height:       1080,
        clips:        []
    };

    try {
        if (!app.project) {
            result.message = "No active project";
            return JSON.stringify(result);
        }

        var sequence = app.project.activeSequence;
        if (!sequence) {
            result.message = "No active sequence";
            return JSON.stringify(result);
        }

        result.sequenceName = sequence.name;

        var TICKS_PER_SECOND = 254016000000;
        var timebaseTicks    = parseFloat(sequence.timebase) || 4240384;
        result.frameRate     = parseFloat((TICKS_PER_SECOND / timebaseTicks).toFixed(4));

        try { result.width  = sequence.frameSizeHorizontal || 1920; } catch (e) {}
        try { result.height = sequence.frameSizeVertical   || 1080; } catch (e) {}

        var videoTracks = sequence.videoTracks;
        for (var t = 0; t < videoTracks.numTracks; t++) {
            var track = videoTracks[t];
            if (!track || !track.clips) continue;
            var numClips = track.clips.numItems;
            for (var c = 0; c < numClips; c++) {
                try {
                    var clip = track.clips[c];
                    if (!clip || !clip.projectItem) continue;

                    var filePath = "";
                    try { filePath = clip.projectItem.getMediaPath(); } catch (e) {}

                    var srcIn  = Math.round(parseFloat(clip.inPoint.ticks)  / timebaseTicks);
                    var srcOut = Math.round(parseFloat(clip.outPoint.ticks) / timebaseTicks);
                    var recIn  = Math.round(parseFloat(clip.start.ticks)    / timebaseTicks);
                    var recOut = Math.round(parseFloat(clip.end.ticks)      / timebaseTicks);

                    // Skip degenerate clips (zero or negative duration)
                    if (srcOut <= srcIn || recOut <= recIn) continue;

                    result.clips.push({
                        trackIndex:        t,
                        filePath:          filePath,
                        fileName:          clip.projectItem.name || "",
                        sourceInFrames:    srcIn,
                        sourceOutFrames:   srcOut,
                        timelineInFrames:  recIn,
                        timelineOutFrames: recOut
                    });
                } catch (e) { /* skip malformed clip */ }
            }
        }

        result.success = true;
        result.message = result.clips.length + " clip(s) across " + videoTracks.numTracks + " track(s)";
        return JSON.stringify(result);
    } catch (error) {
        result.message = "Error reading timeline: " + error.message;
        return JSON.stringify(result);
    }
}

/**
 * Returns all media ProjectItems in the current project with name + file path.
 * Useful for rebuilding the asset-path lookup map after a Premiere restart
 * when temp-file paths may have changed.
 */
function getProjectItems() {
    var result = { items: [] };
    try {
        if (!app.project) return JSON.stringify(result);
        _collectProjectItems(app.project.rootItem, result.items);
    } catch (e) {}
    return JSON.stringify(result);
}

function _collectProjectItems(bin, out) {
    if (!bin || !bin.children) return;
    for (var i = 0; i < bin.children.numItems; i++) {
        var item = bin.children[i];
        if (!item) continue;
        if (item.type === ProjectItemType.BIN) {
            _collectProjectItems(item, out);
        } else {
            var path = "";
            try { path = item.getMediaPath(); } catch (e) {}
            out.push({ name: item.name, path: path });
        }
    }
}

// ============================================================================
// Helper Functions
// ============================================================================

/**
 * Recursively searches for a project item by display name.
 * @param {ProjectItem} bin  - The bin/root to search
 * @param {string}      name - Name to match
 * @returns {ProjectItem|null}
 */
function findProjectItemByName(bin, name) {
    if (!bin || !bin.children) return null;

    for (var i = 0; i < bin.children.numItems; i++) {
        var item = bin.children[i];
        if (item.name === name) return item;
        if (item.type === ProjectItemType.BIN) {
            var found = findProjectItemByName(item, name);
            if (found) return found;
        }
    }
    return null;
}

/**
 * Pads a number with leading zeros.
 * @param {number} num    - Number to pad
 * @param {number} digits - Minimum digit count
 * @returns {string}
 */
function pad(num, digits) {
    var str = "" + Math.floor(num);
    while (str.length < digits) str = "0" + str;
    return str;
}
