{{define "title"}}QFS Мои проекты{{end}}

{{define "content"}}
<div class="space-y-4">
    <div class="flex flex-wrap items-center justify-between gap-3">
        <h1 class="text-2xl font-bold">Мои проекты</h1>
        <div class="flex items-center gap-2">
            <a href="/configs" class="px-4 py-2 bg-gray-200 text-gray-800 rounded hover:bg-gray-300">
                Все конфигурации
            </a>
            <button onclick="openCreateProjectModal()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
                + Новый проект
            </button>
        </div>
    </div>

    <div class="inline-flex rounded-lg border border-gray-200 overflow-hidden">
        <button id="status-active-btn" onclick="setStatus('active')" class="px-4 py-2 text-sm font-medium bg-blue-600 text-white">Активные</button>
        <button id="status-archived-btn" onclick="setStatus('archived')" class="px-4 py-2 text-sm font-medium bg-white text-gray-700 hover:bg-gray-50 border-l border-gray-200">Архив</button>
    </div>

    <div class="max-w-md">
        <input id="projects-search" type="text" placeholder="Поиск проекта по названию или коду"
               class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
    </div>

    <div id="projects-table" class="bg-white rounded-lg shadow p-4 text-gray-500">Загрузка...</div>
</div>

<div id="create-project-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
    <div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4 p-6">
        <h2 class="text-xl font-semibold mb-4">Новый проект</h2>
        <div class="space-y-4">
            <div>
                <label for="create-project-name" class="block text-sm font-medium text-gray-700 mb-1">Название проекта</label>
                <input id="create-project-name" type="text" placeholder="Например: Инфраструктура для OPS-123"
                       class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
            </div>
            <div>
                <label for="create-project-code" class="block text-sm font-medium text-gray-700 mb-1">Код проекта</label>
                <input id="create-project-code" type="text" placeholder="Например: OPS-123"
                       pattern="[A-Za-z0-9._-]+"
                       title="Только буквы, цифры, дефис, точка, подчёркивание"
                       class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
                <p class="text-xs text-gray-400 mt-1">Буквы, цифры, дефис, точка, подчёркивание. Код используется в URL.</p>
            </div>
            <div>
                <label for="create-project-variant" class="block text-sm font-medium text-gray-700 mb-1">Вариант (необязательно)</label>
                <input id="create-project-variant" type="text" placeholder="Например: B200"
                       pattern="[A-Za-z0-9._-]*"
                       title="Только буквы, цифры, дефис, точка, подчёркивание"
                       class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
                <p class="text-xs text-gray-400 mt-1">Используется в URL: /КОД/Вариант</p>
            </div>
            <div>
                <label for="create-project-tracker-url" class="block text-sm font-medium text-gray-700 mb-1">Ссылка на трекер</label>
                <input id="create-project-tracker-url" type="url" placeholder="https://tracker.yandex.ru/OPS-123"
                       class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
            </div>
        </div>
        <div class="flex justify-end gap-2 mt-6">
            <button type="button" onclick="closeCreateProjectModal()" class="px-4 py-2 text-gray-600 hover:text-gray-800">Отмена</button>
            <button type="button" onclick="createProject()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Создать</button>
        </div>
    </div>
</div>

<script>
let status = 'active';
let projectsSearch = '';
let authorSearch = '';
let currentPage = 1;
let perPage = 33;
let sortField = 'created_at';
let sortDir = 'desc';
let createProjectTrackerManuallyEdited = false;
let createProjectLastAutoTrackerURL = '';
let variantsByCode = {};
let variantsLoaded = false;

const trackerBaseURL = 'https://tracker.yandex.ru/';

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text || '';
    return div.innerHTML;
}

function formatMoney(v) {
    return '$' + (v || 0).toLocaleString('ru-RU', {minimumFractionDigits: 2});
}

function formatDateTime(value) {
    if (!value) return '—';
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return '—';
    return date.toLocaleString('ru-RU', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
    });
}

function formatDateParts(value) {
    if (!value) return null;
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return null;
    return {
        date: date.toLocaleDateString('ru-RU', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit'
        }),
        time: date.toLocaleTimeString('ru-RU', {
            hour: '2-digit',
            minute: '2-digit'
        })
    };
}

function formatISODate(value) {
    if (!value) return '—';
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return '—';
    return date.toISOString().slice(0, 10);
}

function renderProjectDateCell(project) {
    const updatedDate = formatISODate(project && project.updated_at);
    const tooltip = [
        'Создан: ' + formatDateTime(project && project.created_at),
        'Изменен: ' + formatDateTime(project && project.updated_at),
        'Автор: ' + ((project && project.owner_username) || '—')
    ].join('\n');
    return '<div class="whitespace-nowrap text-gray-600 cursor-help" title="' + escapeHtml(tooltip) + '">' + escapeHtml(updatedDate) + '</div>';
}

function normalizeVariant(variant) {
    const trimmed = (variant || '').trim();
    return trimmed === '' ? 'main' : trimmed;
}

function renderVariantChips(code, fallbackVariant, fallbackUUID) {
    const variants = variantsByCode[code || ''] || [];
    if (!variants.length) {
        const single = normalizeVariant(fallbackVariant);
        const href = fallbackUUID ? ('/projects/' + fallbackUUID) : '/projects';
        return '<a href="' + href + '" class="inline-flex items-center px-1.5 py-px text-xs leading-5 rounded-full bg-gray-100 text-gray-600 hover:bg-gray-200 hover:text-gray-900">' + escapeHtml(single) + '</a>';
    }
    return variants.map(v => {
        const href = v.uuid ? ('/projects/' + v.uuid) : '/projects';
        return '<a href="' + href + '" class="inline-flex items-center px-1.5 py-px text-xs leading-5 rounded-full bg-gray-100 text-gray-700 hover:bg-gray-200 hover:text-gray-900">' + escapeHtml(v.label) + '</a>';
    }).join(' ');
}

async function loadVariantsIndex() {
    if (variantsLoaded) return;
    try {
        const resp = await fetch('/api/projects/all');
        if (!resp.ok) return;
        const data = await resp.json();
        const allProjects = Array.isArray(data) ? data : (data.projects || []);
        variantsByCode = {};
        allProjects.forEach(p => {
            const code = (p.code || '').trim();
            const variant = normalizeVariant(p.variant);
            if (!variantsByCode[code]) {
                variantsByCode[code] = [];
            }
            if (!variantsByCode[code].some(v => v.label === variant)) {
                variantsByCode[code].push({label: variant, uuid: p.uuid});
            }
        });
        Object.keys(variantsByCode).forEach(code => {
            variantsByCode[code].sort((a, b) => {
                if (a.label === 'main') return -1;
                if (b.label === 'main') return 1;
                return a.label.localeCompare(b.label);
            });
        });
        variantsLoaded = true;
    } catch (e) {
        // ignore
    }
}

function toggleSort(field) {
    if (sortField === field) {
        sortDir = sortDir === 'asc' ? 'desc' : 'asc';
    } else {
        sortField = field;
        sortDir = field === 'name' ? 'asc' : 'desc';
    }
    currentPage = 1;
    loadProjects();
}

function setStatus(value) {
    status = value;
    currentPage = 1;
    document.getElementById('status-active-btn').className = value === 'active'
        ? 'px-4 py-2 text-sm font-medium bg-blue-600 text-white'
        : 'px-4 py-2 text-sm font-medium bg-white text-gray-700 hover:bg-gray-50';
    document.getElementById('status-archived-btn').className = value === 'archived'
        ? 'px-4 py-2 text-sm font-medium bg-blue-600 text-white border-l border-gray-200'
        : 'px-4 py-2 text-sm font-medium bg-white text-gray-700 hover:bg-gray-50 border-l border-gray-200';
    loadProjects();
}

async function loadProjects() {
    const root = document.getElementById('projects-table');
    root.innerHTML = '<div class="text-gray-500">Загрузка...</div>';

    let rows = [];
    let total = 0;
    let totalPages = 0;
    let page = currentPage;
    try {
        const params = new URLSearchParams({
            status: status,
            search: projectsSearch,
            author: authorSearch,
            page: String(currentPage),
            per_page: String(perPage),
            sort: sortField,
            dir: sortDir
        });
        const resp = await fetch('/api/projects?' + params.toString());
        if (!resp.ok) {
            throw new Error('HTTP ' + resp.status);
        }
        const data = await resp.json();
        rows = data.projects || [];
        if (Array.isArray(rows) && rows.length) {
            const byCode = {};
            rows.forEach(p => {
                const codeKey = (p.code || '').trim();
                if (!codeKey) {
                    const fallbackKey = p.uuid || Math.random().toString(36);
                    byCode[fallbackKey] = p;
                    return;
                }
                const variant = (p.variant || '').trim();
                if (!byCode[codeKey]) {
                    byCode[codeKey] = p;
                    return;
                }
                const current = byCode[codeKey];
                const currentVariant = (current.variant || '').trim();
                if (currentVariant !== '' && variant === '') {
                    byCode[codeKey] = p;
                }
            });
            rows = Object.values(byCode);
        }
        total = data.total || 0;
        totalPages = data.total_pages || 0;
        page = data.page || currentPage;
        currentPage = page;
        await loadVariantsIndex();
    } catch (e) {
        root.innerHTML = '<div class="text-red-600">Ошибка загрузки проектов: ' + escapeHtml(String(e.message || e)) + '</div>';
        return;
    }

    let html = '<div class="overflow-x-auto"><table class="w-full table-fixed min-w-[980px]">';
    html += '<thead class="bg-gray-50">';
    html += '<tr>';
    html += '<th class="w-28 px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Дата</th>';
    html += '<th class="w-32 px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Код</th>';
    html += '<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">';
    html += '<button type="button" onclick="toggleSort(\'name\')" class="inline-flex items-center gap-1 hover:text-gray-700">Название';
    if (sortField === 'name') {
        html += sortDir === 'asc' ? ' <span>↑</span>' : ' <span>↓</span>';
    }
    html += '</button></th>';
    html += '<th class="w-24 px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Автор</th>';
    html += '<th class="w-56 px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Варианты</th>';
    html += '<th class="w-14 px-2 py-3 text-right text-xs font-medium text-gray-500 uppercase"></th>';
    html += '</tr>';
    html += '<tr>';
    html += '<th class="px-4 py-2"></th>';
    html += '<th class="px-2 py-2"></th>';
    html += '<th class="px-4 py-2"></th>';
    html += '<th class="px-4 py-2"><input id="projects-author-filter" type="text" value="' + escapeHtml(authorSearch) + '" placeholder="Фильтр автора" class="w-full px-2 py-1 border rounded text-xs focus:ring-1 focus:ring-blue-500 focus:border-blue-500"></th>';
    html += '<th class="px-4 py-2"></th>';
    html += '<th class="px-2 py-2"></th>';
    html += '</tr>';
    html += '</thead><tbody class="divide-y">';

    if (!rows.length) {
        html += '<tr><td colspan="6" class="px-4 py-6 text-sm text-gray-500 text-center">Проектов нет</td></tr>';
    }

        rows.forEach(p => {
            html += '<tr class="hover:bg-gray-50">';
        const displayName = p.name || '';
        const createdBy = p.owner_username || '—';
        const variantChips = renderVariantChips(p.code, p.variant, p.uuid);
        html += '<td class="px-4 py-3 text-sm align-top">' + renderProjectDateCell(p) + '</td>';
        html += '<td class="px-4 py-3 text-sm font-medium align-top break-words"><a class="inline text-blue-600 hover:underline break-all whitespace-normal" href="/projects/' + p.uuid + '">' + escapeHtml(p.code || '—') + '</a></td>';
        html += '<td class="px-4 py-3 text-sm text-gray-700 align-top break-words"><div class="whitespace-normal break-words" title="' + escapeHtml(displayName) + '">' + escapeHtml(displayName || '—') + '</div></td>';
        html += '<td class="px-4 py-3 text-sm text-gray-600 align-top whitespace-nowrap">' + escapeHtml(createdBy) + '</td>';
        html += '<td class="px-4 py-3 text-sm align-top"><div class="flex flex-wrap gap-1">' + variantChips + '</div></td>';
        html += '<td class="px-2 py-3 text-sm text-right"><div class="inline-flex items-center justify-end gap-2">';

        if (p.is_active) {
            if ((p.tracker_url || '').trim() !== '') {
                html += '<a href="' + escapeHtml(p.tracker_url) + '" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center w-5 h-5 text-sky-700 hover:text-sky-900 font-semibold" title="Открыть в трекере">T</a>';
            }
            html += '<button onclick="archiveProject(\'' + p.uuid + '\')" class="text-red-700 hover:text-red-900" title="Удалить (в архив)">';
            html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>';
            html += '</button>';
        }
        html += '</div></td>';
        html += '</tr>';
    });

    html += '</tbody></table></div>';

    if (totalPages > 1) {
        html += '<div class="flex items-center justify-between mt-4 pt-4 border-t">';
        html += '<div class="text-sm text-gray-600">Показано ' + rows.length + ' из ' + total + '</div>';
        html += '<div class="inline-flex items-center gap-1">';
        html += '<button type="button" onclick="goToPage(' + (page - 1) + ')" ' + (page <= 1 ? 'disabled' : '') + ' class="px-3 py-1 text-sm border rounded ' + (page <= 1 ? 'text-gray-300 border-gray-200 cursor-not-allowed' : 'text-gray-700 hover:bg-gray-50') + '">&larr;</button>';
        const startPage = Math.max(1, page - 2);
        const endPage = Math.min(totalPages, page + 2);
        for (let i = startPage; i <= endPage; i++) {
            html += '<button type="button" onclick="goToPage(' + i + ')" class="px-3 py-1 text-sm border rounded ' + (i === page ? 'bg-blue-600 text-white border-blue-600' : 'text-gray-700 border-gray-300 hover:bg-gray-50') + '">' + i + '</button>';
        }
        html += '<button type="button" onclick="goToPage(' + (page + 1) + ')" ' + (page >= totalPages ? 'disabled' : '') + ' class="px-3 py-1 text-sm border rounded ' + (page >= totalPages ? 'text-gray-300 border-gray-200 cursor-not-allowed' : 'text-gray-700 hover:bg-gray-50') + '">&rarr;</button>';
        html += '</div>';
        html += '</div>';
    }

    root.innerHTML = html;

    const authorInput = document.getElementById('projects-author-filter');
    if (authorInput) {
        authorInput.addEventListener('input', function(e) {
            authorSearch = (e.target.value || '').trim();
            currentPage = 1;
            loadProjects();
        });
    }
}

function goToPage(page) {
    if (page < 1) return;
    currentPage = page;
    loadProjects();
}

function buildTrackerURLFromProjectCode(projectCode) {
    const code = (projectCode || '').trim();
    if (!code) return '';
    return trackerBaseURL + encodeURIComponent(code);
}

function openCreateProjectModal() {
    const nameInput = document.getElementById('create-project-name');
    const codeInput = document.getElementById('create-project-code');
    const variantInput = document.getElementById('create-project-variant');
    const trackerInput = document.getElementById('create-project-tracker-url');
    nameInput.value = '';
    codeInput.value = '';
    variantInput.value = '';
    trackerInput.value = '';
    createProjectTrackerManuallyEdited = false;
    createProjectLastAutoTrackerURL = '';
    document.getElementById('create-project-modal').classList.remove('hidden');
    document.getElementById('create-project-modal').classList.add('flex');
    nameInput.focus();
}

function closeCreateProjectModal() {
    document.getElementById('create-project-modal').classList.add('hidden');
    document.getElementById('create-project-modal').classList.remove('flex');
}

function updateCreateProjectTrackerURL() {
    const codeInput = document.getElementById('create-project-code');
    const trackerInput = document.getElementById('create-project-tracker-url');
    const generatedURL = buildTrackerURLFromProjectCode(codeInput.value);
    if (!createProjectTrackerManuallyEdited || trackerInput.value.trim() === '' || trackerInput.value === createProjectLastAutoTrackerURL) {
        trackerInput.value = generatedURL;
        createProjectLastAutoTrackerURL = generatedURL;
    }
}

async function createProject() {
    const nameInput = document.getElementById('create-project-name');
    const codeInput = document.getElementById('create-project-code');
    const variantInput = document.getElementById('create-project-variant');
    const trackerInput = document.getElementById('create-project-tracker-url');
    const name = (nameInput.value || '').trim();
    const code = (codeInput.value || '').trim();
    const variant = (variantInput.value || '').trim();
    if (!code) {
        alert('Введите код проекта');
        return;
    }
    if (!/^[A-Za-z0-9._-]+$/.test(code)) {
        alert('Код проекта содержит недопустимые символы.\nРазрешены: буквы, цифры, дефис, точка, подчёркивание.');
        return;
    }
    if (variant && !/^[A-Za-z0-9._-]+$/.test(variant)) {
        alert('Имя варианта содержит недопустимые символы.\nРазрешены: буквы, цифры, дефис, точка, подчёркивание.');
        return;
    }
    const resp = await fetch('/api/projects', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            name: name,
            code: code,
            variant: variant,
            tracker_url: (trackerInput.value || '').trim()
        })
    });
    if (!resp.ok) {
        if (resp.status === 409) {
            alert('Проект с таким кодом и вариантом уже существует');
            return;
        }
        if (resp.status === 400) {
            const body = await resp.json().catch(() => ({}));
            alert(body.error || 'Некорректный запрос');
            return;
        }
        alert('Не удалось создать проект');
        return;
    }
    closeCreateProjectModal();
    loadProjects();
}

async function renameProject(projectUUID, currentName) {
    const name = prompt('Новое название проекта', currentName);
    if (!name || !name.trim() || name.trim() === currentName) return;
    const resp = await fetch('/api/projects/' + projectUUID, {
        method: 'PUT',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({name: name.trim()})
    });
    if (!resp.ok) {
        if (resp.status === 409) {
            alert('Проект с таким названием уже существует');
            return;
        }
        alert('Не удалось переименовать проект');
        return;
    }
    loadProjects();
}

async function archiveProject(projectUUID) {
    if (!confirm('Переместить проект в архив?')) return;
    const resp = await fetch('/api/projects/' + projectUUID + '/archive', {method: 'POST'});
    if (!resp.ok) {
        alert('Не удалось архивировать проект');
        return;
    }
    loadProjects();
}

async function reactivateProject(projectUUID) {
    const resp = await fetch('/api/projects/' + projectUUID + '/reactivate', {method: 'POST'});
    if (!resp.ok) {
        alert('Не удалось восстановить проект');
        return;
    }
    loadProjects();
}

async function addConfigToProject(projectUUID) {
    const name = prompt('Название новой конфигурации');
    if (!name || !name.trim()) return;
    const resp = await fetch('/api/projects/' + projectUUID + '/configs', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({name: name.trim(), items: [], notes: '', server_count: 1})
    });
    if (!resp.ok) {
        alert('Не удалось создать конфигурацию');
        return;
    }
    loadProjects();
}

async function copyProject(projectUUID, projectName) {
    const newName = prompt('Название копии проекта', projectName + ' (копия)');
    if (!newName || !newName.trim()) return;
    const newCode = prompt('Код проекта', '');
    if (!newCode || !newCode.trim()) return;
    const newVariant = prompt('Вариант (необязательно)', '');

    const createResp = await fetch('/api/projects', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({name: newName.trim(), code: newCode.trim(), variant: (newVariant || '').trim()})
    });
    if (!createResp.ok) {
        if (createResp.status === 409) {
            alert('Проект с таким кодом и вариантом уже существует');
            return;
        }
        alert('Не удалось создать копию проекта');
        return;
    }
    const newProject = await createResp.json();

    const listResp = await fetch('/api/projects/' + projectUUID + '/configs');
    if (!listResp.ok) {
        alert('Проект скопирован без конфигураций (не удалось загрузить исходные конфигурации)');
        loadProjects();
        return;
    }
    const listData = await listResp.json();
    const configs = listData.configurations || [];

    for (const cfg of configs) {
        await fetch('/api/projects/' + newProject.uuid + '/configs/' + cfg.uuid + '/clone', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({name: cfg.name})
        });
    }

    loadProjects();
}

document.addEventListener('DOMContentLoaded', function() {
    loadProjects();

    document.getElementById('projects-search').addEventListener('input', function(e) {
        projectsSearch = (e.target.value || '').trim();
        currentPage = 1;
        loadProjects();
    });

    document.getElementById('create-project-code').addEventListener('input', function() {
        updateCreateProjectTrackerURL();
    });

    document.getElementById('create-project-name').addEventListener('keydown', function(e) {
        if (e.key === 'Enter') {
            e.preventDefault();
            createProject();
        }
    });

    document.getElementById('create-project-tracker-url').addEventListener('input', function(e) {
        createProjectTrackerManuallyEdited = (e.target.value || '').trim() !== createProjectLastAutoTrackerURL;
    });

    document.getElementById('create-project-code').addEventListener('keydown', function(e) {
        if (e.key === 'Enter') {
            e.preventDefault();
            createProject();
        }
    });

    document.getElementById('create-project-tracker-url').addEventListener('keydown', function(e) {
        if (e.key === 'Enter') {
            e.preventDefault();
            createProject();
        }
    });

    document.getElementById('create-project-modal').addEventListener('click', function(e) {
        if (e.target === this) {
            closeCreateProjectModal();
        }
    });

    // Listen for sync completion events from navbar
    window.addEventListener('sync-completed', function(e) {
        // Reset pagination and reload projects list
        loadProjects();
    });
});
</script>
{{end}}

{{template "base" .}}
