const state = {
    recordings: [],
    filtered: [],
    selectedKey: '',
    editing: null
};

const elements = {
    refreshBtn: document.getElementById('refreshBtn'),
    searchInput: document.getElementById('searchInput'),
    typeFilter: document.getElementById('typeFilter'),
    typeFilterControl: document.getElementById('typeFilterControl'),
    typeFilterButton: document.getElementById('typeFilterButton'),
    typeFilterText: document.getElementById('typeFilterText'),
    typeFilterMenu: document.getElementById('typeFilterMenu'),
    clearSearchBtn: document.getElementById('clearSearchBtn'),
    uploadForm: document.getElementById('uploadForm'),
    uploadBtn: document.getElementById('uploadBtn'),
    recordingFile: document.getElementById('recordingFile'),
    fileNameText: document.getElementById('fileNameText'),
    uploadMeetingId: document.getElementById('uploadMeetingId'),
    uploadUserId: document.getElementById('uploadUserId'),
    totalCount: document.getElementById('totalCount'),
    meetingCount: document.getElementById('meetingCount'),
    storageSize: document.getElementById('storageSize'),
    recordingRootText: document.getElementById('recordingRootText'),
    listSummary: document.getElementById('listSummary'),
    loadingState: document.getElementById('loadingState'),
    emptyState: document.getElementById('emptyState'),
    recordingsTableWrap: document.getElementById('recordingsTableWrap'),
    recordingsTableBody: document.getElementById('recordingsTableBody'),
    previewVideo: document.getElementById('previewVideo'),
    previewPlaceholder: document.getElementById('previewPlaceholder'),
    previewTitle: document.getElementById('previewTitle'),
    previewDetails: document.getElementById('previewDetails'),
    editDialog: document.getElementById('editDialog'),
    editForm: document.getElementById('editForm'),
    editFilenameText: document.getElementById('editFilenameText'),
    editMeetingId: document.getElementById('editMeetingId'),
    editOriginalFilename: document.getElementById('editOriginalFilename'),
    editUserId: document.getElementById('editUserId'),
    closeEditBtn: document.getElementById('closeEditBtn'),
    cancelEditBtn: document.getElementById('cancelEditBtn'),
    notification: document.getElementById('notification'),
    notificationText: document.getElementById('notificationText')
};

const typeFilterLabels = {
    all: '全部格式',
    mp4: 'MP4',
    webm: 'WebM'
};

function recordingKey(recording) {
    return `${recording.meetingId}/${recording.filename}`;
}

function escapeHtml(value) {
    return String(value || '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

function formatBytes(bytes) {
    const value = Number(bytes) || 0;
    if (value < 1024) {
        return `${value} B`;
    }

    const units = ['KB', 'MB', 'GB', 'TB'];
    let size = value / 1024;
    let index = 0;
    while (size >= 1024 && index < units.length - 1) {
        size /= 1024;
        index += 1;
    }
    return `${size.toFixed(size >= 10 ? 1 : 2)} ${units[index]}`;
}

function formatDate(value) {
    if (!value) {
        return '-';
    }

    const date = new Date(value);
    if (Number.isNaN(date.getTime())) {
        return '-';
    }

    return date.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
    });
}

function getPersonId(person) {
    return person?.userId || person?.id || '';
}

function getPersonName(person) {
    return person?.name || getPersonId(person) || '-';
}

function getRecordingHost(recording) {
    return recording.host || (recording.userId ? {
        userId: recording.userId,
        id: recording.userId,
        role: 'host'
    } : null);
}

function getRecordingParticipants(recording) {
    return Array.isArray(recording.participants) ? recording.participants : [];
}

function getPeopleSearchText(recording) {
    const host = getRecordingHost(recording);
    const participants = getRecordingParticipants(recording);
    return [
        host?.participantId,
        host?.userId,
        host?.id,
        host?.name,
        ...participants.flatMap(participant => [
            participant.participantId,
            participant.userId,
            participant.id,
            participant.name
        ])
    ].filter(Boolean).join(' ');
}

function renderPersonSummary(person) {
    if (!person) {
        return '-';
    }

    const name = getPersonName(person);
    const id = getPersonId(person);
    return id && id !== name ? `${name} (${id})` : name;
}

function renderPeopleList(people) {
    if (!people.length) {
        return '<div class="recordings-person-empty">暂无参与者</div>';
    }

    return people.map((person) => `
        <div class="recordings-person">
            <img src="${escapeHtml(person.avatar || '/images/p2.png')}" alt="">
            <div>
                <strong>${escapeHtml(getPersonName(person))}</strong>
                <span>${escapeHtml(getPersonId(person) || person.participantId || '-')}</span>
            </div>
        </div>
    `).join('');
}

function setTypeFilter(value) {
    const nextValue = typeFilterLabels[value] ? value : 'all';
    elements.typeFilter.value = nextValue;
    elements.typeFilterText.textContent = typeFilterLabels[nextValue];

    elements.typeFilterMenu.querySelectorAll('[data-type-value]').forEach((option) => {
        const isActive = option.dataset.typeValue === nextValue;
        option.classList.toggle('is-active', isActive);
        option.setAttribute('aria-selected', String(isActive));
    });
}

function setTypeFilterMenuOpen(isOpen) {
    elements.typeFilterControl.classList.toggle('is-open', isOpen);
    elements.typeFilterMenu.classList.toggle('hidden', !isOpen);
    elements.typeFilterButton.setAttribute('aria-expanded', String(isOpen));
}

function showNotification(message, isError = false) {
    elements.notificationText.textContent = message;
    elements.notification.classList.toggle('recordings-notification-error', isError);
    elements.notification.classList.add('recordings-notification-visible');
    window.clearTimeout(showNotification.timer);
    showNotification.timer = window.setTimeout(() => {
        elements.notification.classList.remove('recordings-notification-visible');
    }, 2600);
}

async function requestJson(url, options = {}) {
    const response = await fetch(url, options);
    const payload = await response.json().catch(() => ({}));
    if (!response.ok || payload.success === false) {
        throw new Error(payload.message || `请求失败: ${response.status}`);
    }
    return payload;
}

function setLoading(isLoading) {
    elements.loadingState.classList.toggle('hidden', !isLoading);
    elements.recordingsTableWrap.classList.toggle('hidden', isLoading || state.filtered.length === 0);
    elements.emptyState.classList.toggle('hidden', isLoading || state.filtered.length > 0);
}

async function loadRecordings() {
    setLoading(true);
    try {
        const payload = await requestJson('/api/recordings');
        state.recordings = payload.recordings || [];
        elements.recordingRootText.textContent = payload.root || 'recordings';
        applyFilters();
        const selected = state.filtered.find(item => recordingKey(item) === state.selectedKey) || state.filtered[0];
        selectRecording(selected || null);
    } catch (error) {
        state.recordings = [];
        applyFilters();
        selectRecording(null);
        showNotification(error.message, true);
    } finally {
        setLoading(false);
    }
}

function applyFilters() {
    const query = elements.searchInput.value.trim().toLowerCase();
    const type = elements.typeFilter.value;

    state.filtered = state.recordings.filter((recording) => {
        const extension = (recording.filename || '').split('.').pop().toLowerCase();
        const haystack = [
            recording.meetingId,
            recording.filename,
            recording.originalFilename,
            recording.userId,
            getPeopleSearchText(recording)
        ].join(' ').toLowerCase();
        return (type === 'all' || extension === type) && (!query || haystack.includes(query));
    });

    elements.clearSearchBtn.classList.toggle('hidden', !query && type === 'all');
    renderSummary();
    renderTable();
    setLoading(false);
}

function renderSummary() {
    const meetings = new Set(state.recordings.map(recording => recording.meetingId));
    const totalSize = state.recordings.reduce((sum, recording) => sum + (Number(recording.size) || 0), 0);

    elements.totalCount.textContent = state.recordings.length;
    elements.meetingCount.textContent = meetings.size;
    elements.storageSize.textContent = formatBytes(totalSize);
    elements.listSummary.textContent = `当前显示 ${state.filtered.length} 条，共 ${state.recordings.length} 条`;
}

function renderTable() {
    elements.recordingsTableBody.innerHTML = state.filtered.map((recording) => {
        const key = recordingKey(recording);
        const active = key === state.selectedKey ? 'recordings-row-active' : '';
        const ext = escapeHtml((recording.filename || '').split('.').pop().toUpperCase());
        const host = getRecordingHost(recording);
        const participants = getRecordingParticipants(recording);

        return `
            <tr class="${active}" data-key="${escapeHtml(key)}">
                <td>
                    <button class="recordings-file-cell" data-action="select" data-key="${escapeHtml(key)}">
                        <span class="recordings-file-icon">${ext}</span>
                        <span class="min-w-0">
                            <span class="recordings-file-name">${escapeHtml(recording.originalFilename || recording.filename)}</span>
                            <span class="recordings-file-sub">${escapeHtml(recording.filename)}</span>
                        </span>
                    </button>
                </td>
                <td>${escapeHtml(recording.meetingId)}</td>
                <td>${escapeHtml(renderPersonSummary(host))}</td>
                <td>${participants.length}</td>
                <td>${formatBytes(recording.size)}</td>
                <td>${formatDate(recording.uploadedAt)}</td>
                <td>
                    <div class="recordings-actions">
                        <button class="recordings-icon-btn" data-action="preview" data-key="${escapeHtml(key)}" title="预览">
                            <i class="fas fa-play"></i>
                        </button>
                        <a class="recordings-icon-btn" href="${escapeHtml(recording.downloadUrl)}" title="下载">
                            <i class="fas fa-download"></i>
                        </a>
                        <button class="recordings-icon-btn" data-action="edit" data-key="${escapeHtml(key)}" title="编辑">
                            <i class="fas fa-pen"></i>
                        </button>
                        <button class="recordings-icon-btn recordings-danger" data-action="delete" data-key="${escapeHtml(key)}" title="删除">
                            <i class="fas fa-trash"></i>
                        </button>
                    </div>
                </td>
            </tr>
        `;
    }).join('');
}

function findRecording(key) {
    return state.recordings.find(recording => recordingKey(recording) === key);
}

function selectRecording(recording) {
    if (!recording) {
        state.selectedKey = '';
        elements.previewVideo.removeAttribute('src');
        elements.previewVideo.load();
        elements.previewPlaceholder.classList.remove('hidden');
        elements.previewTitle.textContent = '未选择录制';
        elements.previewDetails.innerHTML = '<p>从左侧列表选择文件后，可播放、下载、编辑或删除。</p>';
        renderTable();
        return;
    }

    state.selectedKey = recordingKey(recording);
    const host = getRecordingHost(recording);
    const participants = getRecordingParticipants(recording);
    elements.previewVideo.src = recording.streamUrl;
    elements.previewPlaceholder.classList.add('hidden');
    elements.previewTitle.textContent = recording.originalFilename || recording.filename;
    elements.previewDetails.innerHTML = `
        <div class="recordings-detail-row"><span>会议 ID</span><strong>${escapeHtml(recording.meetingId)}</strong></div>
        <div class="recordings-detail-row"><span>文件名</span><strong>${escapeHtml(recording.filename)}</strong></div>
        <div class="recordings-detail-row"><span>格式</span><strong>${escapeHtml(recording.mimetype)}</strong></div>
        <div class="recordings-detail-row"><span>大小</span><strong>${formatBytes(recording.size)}</strong></div>
        <div class="recordings-detail-row"><span>用户 ID</span><strong>${escapeHtml(recording.userId || '-')}</strong></div>
        <div class="recordings-detail-row"><span>上传时间</span><strong>${formatDate(recording.uploadedAt)}</strong></div>
        <div class="recordings-people-section">
            <div class="recordings-people-title">房主</div>
            ${renderPeopleList(host ? [host] : [])}
        </div>
        <div class="recordings-people-section">
            <div class="recordings-people-title">参与者 (${participants.length})</div>
            ${renderPeopleList(participants)}
        </div>
        <div class="recordings-preview-actions">
            <a class="recordings-primary-btn" href="${escapeHtml(recording.downloadUrl)}">
                <i class="fas fa-download"></i>
                <span>下载</span>
            </a>
            <button class="recordings-secondary-btn" type="button" data-preview-action="edit">编辑</button>
        </div>
    `;
    renderTable();
}

function openEdit(recording) {
    if (!recording) {
        return;
    }

    state.editing = recording;
    elements.editFilenameText.textContent = recording.filename;
    elements.editMeetingId.value = recording.meetingId || '';
    elements.editOriginalFilename.value = recording.originalFilename || recording.filename || '';
    elements.editUserId.value = recording.userId || '';
    elements.editDialog.classList.remove('hidden');
    elements.editDialog.classList.add('flex');
    elements.editMeetingId.focus();
}

function closeEdit() {
    state.editing = null;
    elements.editDialog.classList.add('hidden');
    elements.editDialog.classList.remove('flex');
}

async function handleUpload(event) {
    event.preventDefault();
    const file = elements.recordingFile.files[0];
    if (!file) {
        showNotification('请选择录制文件', true);
        return;
    }

    const formData = new FormData();
    formData.append('recording', file, file.name);
    formData.append('filename', file.name);
    formData.append('meetingId', elements.uploadMeetingId.value.trim());
    formData.append('userId', elements.uploadUserId.value.trim());

    elements.uploadBtn.disabled = true;
    try {
        await requestJson('/api/recordings', {
            method: 'POST',
            body: formData
        });
        elements.uploadForm.reset();
        elements.fileNameText.textContent = '选择 MP4 或 WebM 文件';
        showNotification('录制已上传');
        await loadRecordings();
    } catch (error) {
        showNotification(error.message, true);
    } finally {
        elements.uploadBtn.disabled = false;
    }
}

async function handleEdit(event) {
    event.preventDefault();
    if (!state.editing) {
        return;
    }

    const recording = state.editing;
    try {
        const payload = await requestJson(`/api/recordings/${encodeURIComponent(recording.meetingId)}/${encodeURIComponent(recording.filename)}`, {
            method: 'PATCH',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                meetingId: elements.editMeetingId.value.trim(),
                originalFilename: elements.editOriginalFilename.value.trim(),
                userId: elements.editUserId.value.trim()
            })
        });
        state.selectedKey = recordingKey(payload.recording);
        closeEdit();
        showNotification('录制信息已更新');
        await loadRecordings();
    } catch (error) {
        showNotification(error.message, true);
    }
}

async function deleteRecording(recording) {
    if (!recording) {
        return;
    }

    const confirmed = window.confirm(`确定删除录制文件 "${recording.originalFilename || recording.filename}" 吗？`);
    if (!confirmed) {
        return;
    }

    try {
        await requestJson(`/api/recordings/${encodeURIComponent(recording.meetingId)}/${encodeURIComponent(recording.filename)}`, {
            method: 'DELETE'
        });
        if (state.selectedKey === recordingKey(recording)) {
            state.selectedKey = '';
        }
        showNotification('录制已删除');
        await loadRecordings();
    } catch (error) {
        showNotification(error.message, true);
    }
}

function bindEvents() {
    elements.refreshBtn.addEventListener('click', loadRecordings);
    elements.searchInput.addEventListener('input', applyFilters);
    elements.typeFilter.addEventListener('change', applyFilters);
    elements.typeFilterButton.addEventListener('click', () => {
        setTypeFilterMenuOpen(!elements.typeFilterControl.classList.contains('is-open'));
    });
    elements.typeFilterMenu.addEventListener('click', (event) => {
        const option = event.target.closest('[data-type-value]');
        if (!option) {
            return;
        }

        setTypeFilter(option.dataset.typeValue);
        setTypeFilterMenuOpen(false);
        applyFilters();
    });
    document.addEventListener('click', (event) => {
        if (!elements.typeFilterControl.contains(event.target)) {
            setTypeFilterMenuOpen(false);
        }
    });
    document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape') {
            setTypeFilterMenuOpen(false);
        }
    });
    elements.clearSearchBtn.addEventListener('click', () => {
        elements.searchInput.value = '';
        setTypeFilter('all');
        applyFilters();
    });
    elements.recordingFile.addEventListener('change', () => {
        const file = elements.recordingFile.files[0];
        elements.fileNameText.textContent = file ? file.name : '选择 MP4 或 WebM 文件';
    });
    elements.uploadForm.addEventListener('submit', handleUpload);
    elements.editForm.addEventListener('submit', handleEdit);
    elements.closeEditBtn.addEventListener('click', closeEdit);
    elements.cancelEditBtn.addEventListener('click', closeEdit);
    elements.editDialog.addEventListener('click', (event) => {
        if (event.target === elements.editDialog) {
            closeEdit();
        }
    });

    elements.recordingsTableBody.addEventListener('click', (event) => {
        const control = event.target.closest('[data-action]');
        if (!control) {
            return;
        }

        const recording = findRecording(control.dataset.key);
        const action = control.dataset.action;
        if (action === 'select' || action === 'preview') {
            selectRecording(recording);
            if (action === 'preview') {
                elements.previewVideo.play().catch(() => undefined);
            }
        } else if (action === 'edit') {
            openEdit(recording);
        } else if (action === 'delete') {
            deleteRecording(recording);
        }
    });

    elements.previewDetails.addEventListener('click', (event) => {
        const control = event.target.closest('[data-preview-action]');
        if (control && control.dataset.previewAction === 'edit') {
            openEdit(findRecording(state.selectedKey));
        }
    });
}

bindEvents();
setTypeFilter(elements.typeFilter.value);
loadRecordings();
