// Wild Dragon MAM - API Helper Module

const API_BASE = '/api/v1';
const CAPTURE_BASE = '/capture';

// Session ID for the active capture — set on start, cleared on stop
let _captureSessionId = null;

/**
 * Wrapper around fetch with JSON parsing and error handling
 */
async function api(path, options = {}) {
    const url = `${API_BASE}${path}`;
    const config = {
        credentials: 'include',
        headers: {
            'Content-Type': 'application/json',
            ...options.headers,
        },
        ...options,
    };

    try {
        const response = await fetch(url, config);

        if (!response.ok) {
            const error = await response.json().catch(() => ({ message: response.statusText }));
            throw new Error(error.message || `API Error: ${response.status}`);
        }

        const data = await response.json();
        return { success: true, data };
    } catch (error) {
        console.error(`API Error on ${path}:`, error);
        return { success: false, error: error.message };
    }
}

/**
 * Wrapper around fetch for capture endpoints (goes directly to capture service via nginx)
 */
async function captureApi(path, options = {}) {
    const url = `${CAPTURE_BASE}${path}`;
    const config = {
        credentials: 'include',
        headers: {
            'Content-Type': 'application/json',
            ...options.headers,
        },
        ...options,
    };

    try {
        const response = await fetch(url, config);

        if (!response.ok) {
            const error = await response.json().catch(() => ({ message: response.statusText }));
            throw new Error(error.message || `Capture API Error: ${response.status}`);
        }

        const data = await response.json();
        return { success: true, data };
    } catch (error) {
        console.error(`Capture API Error on ${path}:`, error);
        return { success: false, error: error.message };
    }
}

// ============================================================
// ASSET API CALLS
// ============================================================

async function getAssets(filters = {}) {
    const params = new URLSearchParams(filters);
    const path = `/assets${params.toString() ? '?' + params.toString() : ''}`;
    const r = await api(path);
    // API returns { assets, total }. Callers expect r.data to be the array,
    // so unwrap here — but preserve total as a sibling for any caller that wants it.
    if (r.success && r.data && typeof r.data === 'object' && Array.isArray(r.data.assets)) {
        r.total = r.data.total;
        r.data = r.data.assets;
    }
    return r;
}

async function getAsset(assetId) {
    return api(`/assets/${assetId}`);
}

async function getAssetStreamUrl(assetId) {
    return api(`/assets/${assetId}/stream`);
}

async function updateAsset(assetId, data) {
    return api(`/assets/${assetId}`, {
        method: 'PATCH',
        body: JSON.stringify(data),
    });
}

async function searchAssets(query) {
    return api(`/assets?q=${encodeURIComponent(query)}`);
}

async function getAssetMetadata(assetId) {
    return api(`/assets/${assetId}`);
}

async function deleteAsset(assetId, { hard = false } = {}) {
    const qs = hard ? '?hard=true' : '';
    return api(`/assets/${assetId}${qs}`, { method: 'DELETE' });
}

async function retryAsset(assetId) {
    return api(`/assets/${assetId}/retry`, { method: 'POST' });
}

async function moveAsset(assetId, binId) {
    return api(`/assets/${assetId}`, {
        method: 'PATCH',
        body: JSON.stringify({ bin_id: binId || null }),
    });
}

async function copyAsset(assetId, { binId, projectId } = {}) {
    return api(`/assets/${assetId}/copy`, {
        method: 'POST',
        body: JSON.stringify({ binId: binId || null, projectId: projectId || null }),
    });
}

// ============================================================
// PROJECT API CALLS
// ============================================================

async function getProjects() {
    return api('/projects');
}

async function getProject(projectId) {
    return api(`/projects/${projectId}`);
}

async function createProject(name, description = '') {
    return api('/projects', {
        method: 'POST',
        body: JSON.stringify({ name, description }),
    });
}

async function updateProject(projectId, data) {
    return api(`/projects/${projectId}`, {
        method: 'PATCH',
        body: JSON.stringify(data),
    });
}

async function deleteProject(projectId) {
    return api(`/projects/${projectId}`, {
        method: 'DELETE',
    });
}

// ============================================================
// BIN API CALLS
// ============================================================

async function getBins(projectId) {
    return api(`/bins?project_id=${projectId}`);
}

async function getBin(projectId, binId) {
    return api(`/bins/${binId}`);
}

async function createBin(projectId, name, description = '') {
    return api('/bins', {
        method: 'POST',
        body: JSON.stringify({ project_id: projectId, name }),
    });
}

async function updateBin(projectId, binId, data) {
    return api(`/bins/${binId}`, {
        method: 'PATCH',
        body: JSON.stringify(data),
    });
}

async function deleteBin(projectId, binId) {
    return api(`/bins/${binId}`, {
        method: 'DELETE',
    });
}

// ============================================================
// CAPTURE API CALLS
// ============================================================

async function getCaptureDevices() {
    const result = await captureApi('/devices');
    if (result.success && result.data) {
        const raw = Array.isArray(result.data)
            ? result.data
            : (result.data.devices || []);
        result.data = raw.map(d => ({
            id:        d.index !== undefined ? d.index : d.id,
            name:      d.name,
            interface: d.interface || 'DeckLink',
        }));
    }
    return result;
}

async function getCaptureStatus() {
    return captureApi('/status');
}

async function getRecordingStatus() {
    return captureApi('/status');
}

async function startRecording(deviceIndex, projectId, binId, clipName) {
    const result = await captureApi('/start', {
        method: 'POST',
        body: JSON.stringify({
            device:     parseInt(deviceIndex, 10),
            project_id: projectId,
            bin_id:     binId || null,
            clip_name:  clipName,
        }),
    });
    if (result.success && result.data && result.data.sessionId) {
        _captureSessionId = result.data.sessionId;
    }
    return result;
}

async function stopRecording() {
    let sessionId = _captureSessionId;

    if (!sessionId) {
        const statusResult = await captureApi('/status');
        if (statusResult.success && statusResult.data && statusResult.data.sessionId) {
            sessionId = statusResult.data.sessionId;
        }
    }

    const result = await captureApi('/stop', {
        method: 'POST',
        body: JSON.stringify({ session_id: sessionId }),
    });

    if (result.success) {
        _captureSessionId = null;
    }
    return result;
}

async function getRecentCaptures(limit = 10) {
    const r = await api(`/assets?limit=${limit}`);
    if (r.success && r.data && typeof r.data === 'object' && Array.isArray(r.data.assets)) {
        r.total = r.data.total;
        r.data = r.data.assets;
    }
    return r;
}

async function getRecordingTimecode() {
    return { success: true, data: { timecode: null } };
}

// ============================================================
// UTILITY FUNCTIONS
// ============================================================

function formatFileSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
}

function formatDuration(seconds) {
    if (!seconds || seconds < 0) return '00:00:00';
    const hours   = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs    = Math.floor(seconds % 60);
    return [hours, minutes, secs].map(v => v.toString().padStart(2, '0')).join(':');
}

function getStatusLabel(status) {
    const labels = {
        ingesting:  'Ingesting',
        processing: 'Processing',
        ready:      'Ready',
        error:      'Error',
        archived:   'Archived',
    };
    return labels[status] || status;
}

function getStatusBadgeClass(status) {
    return `badge-${status}`;
}

function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => { clearTimeout(timeout); func(...args); };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

function throttle(func, limit) {
    let inThrottle;
    return function(...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

// ============================================================
// UPLOAD API CALLS
// ============================================================

async function initUpload(data) {
    const body = {
        filename:    data.filename,
        fileSize:    data.file_size  || data.fileSize,
        contentType: data.content_type || data.contentType,
        projectId:   data.project_id || data.projectId,
        binId:       data.bin_id     || data.binId || null,
        tags:        data.tags       || null,
    };
    return api('/upload/init', { method: 'POST', body: JSON.stringify(body) });
}

async function completeUpload(data) {
    const body = {
        uploadId: data.upload_id || data.uploadId,
        key:      data.key,
        assetId:  data.asset_id  || data.assetId,
        parts:    (data.parts || []).map(p => ({
            partNumber: p.part_number || p.partNumber,
            ETag:       p.etag        || p.ETag,
        })),
    };
    return api('/upload/complete', { method: 'POST', body: JSON.stringify(body) });
}

async function abortUpload(data) {
    const body = {
        uploadId: data.upload_id || data.uploadId,
        key:      data.key,
        assetId:  data.asset_id  || data.assetId,
    };
    return api('/upload/abort', { method: 'POST', body: JSON.stringify(body) });
}

async function uploadPart(formData) {
    try {
        const response = await fetch('/api/v1/upload/part', {
            method: 'POST',
            credentials: 'include',
            body: formData,
        });
        if (!response.ok) throw new Error(`Upload part failed: ${response.status}`);
        const data = await response.json();
        return { success: true, data };
    } catch (error) {
        return { success: false, error: error.message };
    }
}

async function simpleUpload(formData) {
    try {
        const response = await fetch('/api/v1/upload/simple', {
            method: 'POST',
            credentials: 'include',
            body: formData,
        });
        if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
        const data = await response.json();
        return { success: true, data };
    } catch (error) {
        return { success: false, error: error.message };
    }
}

// ============================================================
// RECORDER API CALLS
// ============================================================

async function getRecorders() {
    return api('/recorders');
}

async function createRecorder(data) {
    return api('/recorders', { method: 'POST', body: JSON.stringify(data) });
}

async function patchRecorder(id, data) {
    return api(`/recorders/${id}`, { method: 'PATCH', body: JSON.stringify(data) });
}

async function startRecorder(id) {
    return api(`/recorders/${id}/start`, { method: 'POST' });
}

async function stopRecorder(id) {
    return api(`/recorders/${id}/stop`, { method: 'POST' });
}

async function deleteRecorder(id) {
    return api(`/recorders/${id}`, { method: 'DELETE' });
}

async function getRecorderStatus(id) {
    return api(`/recorders/${id}/status`);
}

// ============================================================
// USERS API CALLS (admin)
// ============================================================

async function getUsers() {
    return api('/users');
}

async function createUser(data) {
    return api('/users', { method: 'POST', body: JSON.stringify(data) });
}

async function updateUser(id, data) {
    return api(`/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) });
}

async function deleteUser(id) {
    return api(`/users/${id}`, { method: 'DELETE' });
}

// ============================================================
// GROUPS API CALLS (admin)
// ============================================================

async function getGroups() {
    return api('/groups');
}

async function createGroup(data) {
    return api('/groups', { method: 'POST', body: JSON.stringify(data) });
}

async function updateGroup(id, data) {
    return api(`/groups/${id}`, { method: 'PATCH', body: JSON.stringify(data) });
}

async function deleteGroup(id) {
    return api(`/groups/${id}`, { method: 'DELETE' });
}

async function getGroupMembers(id) {
    return api(`/groups/${id}/members`);
}

async function addGroupMember(groupId, userId) {
    return api(`/groups/${groupId}/members`, {
        method: 'POST',
        body: JSON.stringify({ user_id: userId }),
    });
}

async function removeGroupMember(groupId, userId) {
    return api(`/groups/${groupId}/members/${userId}`, { method: 'DELETE' });
}

// ============================================================
// TOKENS API CALLS
// ============================================================

async function getTokens() {
    return api('/tokens');
}

async function createToken(data) {
    return api('/tokens', { method: 'POST', body: JSON.stringify(data) });
}

async function revokeToken(id) {
    return api(`/tokens/${id}`, { method: 'DELETE' });
}

// ============================================================
// SEQUENCE API CALLS
// ============================================================

async function getSequences(projectId) {
  return api(`/sequences?project_id=${projectId}`);
}

async function createSequence(data) {
  return api('/sequences', {
    method: 'POST',
    body: JSON.stringify(data),
  });
}

async function getSequence(sequenceId) {
  return api(`/sequences/${sequenceId}`);
}

async function updateSequence(sequenceId, data) {
  return api(`/sequences/${sequenceId}`, {
    method: 'PUT',
    body: JSON.stringify(data),
  });
}

async function deleteSequence(sequenceId) {
  return api(`/sequences/${sequenceId}`, { method: 'DELETE' });
}

/**
 * Replace all clips in a sequence.
 * @param {string} sequenceId
 * @param {Array<{asset_id, track, timeline_in_frames, timeline_out_frames, source_in_frames, source_out_frames}>} clips
 */
async function syncSequenceClips(sequenceId, clips) {
  return api(`/sequences/${sequenceId}/clips`, {
    method: 'PUT',
    body: JSON.stringify(clips),
  });
}

/**
 * Download EDL for the V1 track of a sequence.
 * Triggers a file download in the browser.
 */
async function exportSequenceEDL(sequenceId, filename) {
  try {
    const response = await fetch(`${API_BASE}/sequences/${sequenceId}/export/edl`, {
      method: 'POST',
      credentials: 'include',
    });
    if (!response.ok) throw new Error(`EDL export failed: ${response.status}`);
    const blob = await response.blob();
    const url  = URL.createObjectURL(blob);
    const a    = document.createElement('a');
    a.href     = url;
    a.download = filename || 'sequence.edl';
    a.click();
    URL.revokeObjectURL(url);
    return { success: true };
  } catch (error) {
    return { success: false, error: error.message };
  }
}
