<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}인트라넷 회계 시스템{% endblock %}</title>
    <style>
        :root {
            --bg-a: #f6f6f7;
            --bg-b: #ececef;
            --panel: rgba(255, 255, 255, 0.94);
            --ink: #161616;
            --muted: #73777f;
            --line: #d9dde3;
            --accent: #111111;
            --accent-strong: #000000;
            --warn: #fff2cb;
            --table-alt: #f5f6f8;
            --white: #ffffff;
            --page-gutter: clamp(14px, 1.8vw, 24px);
            --panel-pad: clamp(16px, 1.4vw, 20px);
            --page-frame-width: min(1520px, calc(100vw - (var(--page-gutter) * 2)));
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: "SUIT", "Noto Sans KR", "Malgun Gothic", sans-serif;
            color: var(--ink);
            background:
                radial-gradient(circle at top left, rgba(255, 255, 255, 0.92), transparent 24%),
                linear-gradient(180deg, var(--bg-a), var(--bg-b));
            min-height: 100vh;
            padding: var(--page-gutter);
        }

        .page {
            width: min(100%, var(--page-frame-width));
            margin: 0 auto;
            display: grid;
            gap: var(--page-gutter);
        }

        .page > * {
            width: 100%;
        }

        .nav {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            align-items: center;
            background: rgba(255, 255, 255, 0.9);
            border: 1px solid var(--line);
            border-radius: 18px;
            padding: 8px;
            box-shadow: 0 10px 24px rgba(21, 24, 29, 0.06);
        }

        .nav-spacer {
            flex: 1 1 auto;
            min-width: 12px;
        }

        .nav a {
            text-decoration: none;
            color: var(--ink);
            padding: 9px 13px;
            border-radius: 10px;
            font-weight: 700;
            font-size: 14px;
            transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
        }

        .nav a.active {
            background: var(--accent);
            color: var(--white);
        }

        .nav a:hover {
            background: #f3f4f6;
        }

        .panel {
            background: var(--panel);
            border: 1px solid var(--line);
            border-radius: 18px;
            padding: var(--panel-pad);
            box-shadow: 0 10px 24px rgba(21, 24, 29, 0.045);
            backdrop-filter: blur(6px);
        }

        .section-title {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 14px;
        }

        .section-title h2 {
            font-size: 21px;
            letter-spacing: -0.03em;
        }

        .section-title p {
            color: var(--muted);
            font-size: 14px;
        }

        .message {
            background: var(--warn);
            border: 1px solid #ead98a;
            color: #624c0b;
            border-radius: 14px;
            padding: 14px 16px;
            line-height: 1.6;
        }

        .stats {
            display: grid;
            grid-template-columns: repeat(5, minmax(0, 1fr));
            gap: 14px;
        }

        .summary-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 18px;
            margin-top: 18px;
        }

        .stat-card {
            background: var(--white);
            border: 1px solid var(--line);
            border-radius: 14px;
            padding: 14px 15px 13px;
            box-shadow: inset 0 1px 0 rgba(255,255,255,0.7);
        }

        .stat-card .label {
            color: var(--muted);
            font-size: 13px;
            margin-bottom: 6px;
            letter-spacing: 0.01em;
            font-weight: 700;
        }

        .stat-card .value {
            font-size: clamp(23px, 2vw, 38px);
            font-weight: 800;
            line-height: 1.1;
            letter-spacing: -0.04em;
            word-break: break-word;
        }

        .stat-card .meta {
            margin-top: 6px;
            color: var(--muted);
            font-size: 12px;
            line-height: 1.45;
        }

        .two-col {
            display: grid;
            grid-template-columns: 0.92fr 1.08fr;
            gap: 20px;
        }

        .stack {
            display: grid;
            gap: 20px;
        }

        form {
            display: grid;
            gap: 14px;
        }

        .upload-box {
            background: linear-gradient(180deg, #fbfbfc, #f1f3f6);
            border: 1px dashed #c5ccd6;
            border-radius: 14px;
            padding: 18px;
        }

        .upload-box p {
            color: var(--muted);
            line-height: 1.65;
            margin-bottom: 10px;
        }

        .form-grid {
            display: grid;
            grid-template-columns: repeat(4, minmax(0, 1fr));
            gap: 12px;
        }

        .field {
            display: grid;
            gap: 6px;
        }

        .field-wide {
            grid-column: span 2;
        }

        .field-full {
            grid-column: 1 / -1;
        }

        label {
            font-size: 12px;
            font-weight: 700;
            color: var(--muted);
        }

        input,
        select,
        textarea,
        button {
            font: inherit;
        }

        input[type="text"],
        input[type="number"],
        input[type="date"],
        input[type="file"],
        select,
        textarea {
            width: 100%;
            border: 1px solid var(--line);
            background: #fcfcfd;
            border-radius: 10px;
            padding: 10px 12px;
            color: var(--ink);
            box-shadow: inset 0 1px 2px rgba(16, 24, 40, 0.03);
        }

        textarea {
            min-height: 96px;
            resize: vertical;
        }

        input:focus,
        select:focus,
        textarea:focus {
            outline: none;
            border-color: var(--accent);
            box-shadow: 0 0 0 3px rgba(17, 17, 17, 0.08);
        }

        .actions {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            align-items: center;
        }

        button,
        .button-link {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            border-radius: 10px;
            border: 1px solid transparent;
            padding: 9px 14px;
            background: var(--accent);
            color: var(--white);
            font-weight: 700;
            font-size: 14px;
            cursor: pointer;
            text-decoration: none;
            transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease, border-color 0.16s ease;
            box-shadow: 0 8px 18px rgba(17, 17, 17, 0.14);
        }

        button:hover,
        .button-link:hover {
            background: var(--accent-strong);
            transform: translateY(-1px);
        }

        .button-secondary {
            background: #ffffff;
            color: #1b1d21;
            border-color: var(--line);
            box-shadow: none;
        }

        .button-icon {
            width: 38px;
            height: 38px;
            min-width: 38px;
            padding: 0;
            border-radius: 10px;
            box-shadow: none;
            flex: 0 0 auto;
        }

        .button-icon svg {
            width: 16px;
            height: 16px;
            stroke: currentColor;
            fill: none;
            stroke-width: 1.8;
            stroke-linecap: round;
            stroke-linejoin: round;
        }

        .button-icon.button-secondary svg {
            stroke: #1b1d21;
        }

        .button-icon.danger-lite svg {
            stroke: #a93a3a;
        }

        .sr-only {
            position: absolute;
            width: 1px;
            height: 1px;
            padding: 0;
            margin: -1px;
            overflow: hidden;
            clip: rect(0, 0, 0, 0);
            white-space: nowrap;
            border: 0;
        }

        .table-wrap {
            overflow: auto;
            border: 1px solid var(--line);
            border-radius: 14px;
            background: var(--white);
        }

        table {
            width: 100%;
            border-collapse: collapse;
            min-width: 780px;
        }

        th,
        td {
            padding: 12px 14px;
            border-bottom: 1px solid var(--line);
            text-align: left;
            vertical-align: top;
            font-size: 14px;
        }

        th {
            position: sticky;
            top: 0;
            background: #eff5f7;
            color: #345061;
            z-index: 1;
        }

        tbody tr:nth-child(even) td {
            background: var(--table-alt);
        }

        .empty {
            padding: 24px;
            color: var(--muted);
            text-align: center;
        }

        .search-box {
            margin: 16px 0;
        }

        .mono {
            font-family: "Consolas", "Courier New", monospace;
            font-size: 13px;
        }

        .sync-status {
            margin-left: auto;
            max-width: 240px;
            border: 1px solid var(--line);
            border-radius: 999px;
            background: rgba(248, 250, 252, 0.92);
            box-shadow: none;
            padding: 6px 10px;
            display: inline-flex;
            align-items: center;
            gap: 8px;
            backdrop-filter: blur(6px);
        }

        .sync-status-head {
            display: inline-flex;
            align-items: center;
            gap: 8px;
        }

        .sync-status-title {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            font-size: 12px;
            font-weight: 800;
            white-space: nowrap;
        }

        .sync-dot {
            width: 8px;
            height: 8px;
            border-radius: 999px;
            background: #9aa3af;
        }

        .sync-dot.online {
            background: #16a34a;
            box-shadow: 0 0 0 4px rgba(22, 163, 74, 0.12);
        }

        .sync-dot.error {
            background: #dc2626;
            box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.12);
        }

        .sync-pill {
            display: none;
        }

        .sync-meta {
            display: none;
        }

        .sync-meta strong {
            color: var(--ink);
            font-weight: 700;
        }

        @media (max-width: 1200px) {
            .stats {
                grid-template-columns: repeat(2, minmax(0, 1fr));
            }

            .summary-grid,
            .two-col {
                grid-template-columns: 1fr;
            }

            .form-grid {
                grid-template-columns: repeat(2, minmax(0, 1fr));
            }
        }

        @media (max-width: 720px) {
            .stats,
            .form-grid {
                grid-template-columns: 1fr;
            }

            .field-wide,
            .field-full {
                grid-column: auto;
            }

            .sync-status {
                width: 100%;
                justify-content: center;
            }
        }
    </style>
    {% block head_extra %}{% endblock %}
</head>
<body>
<div class="page">
    <nav class="nav">
        <a href="/" class="{% if request.url.path == '/' %}active{% endif %}">대시보드</a>
        <a href="/projects" class="{% if request.url.path == '/projects' %}active{% endif %}">프로젝트 정보</a>
        <a href="/annual-summary" class="{% if request.url.path == '/annual-summary' %}active{% endif %}">연도별 수익/비용</a>
        <div class="nav-spacer"></div>
        <aside
            class="sync-status"
            id="syncStatusWidget"
            data-data-version="{{ data_version or '' }}"
            data-refresh-url="{{ request.url.path }}{% if request.url.query %}?{{ request.url.query }}{% endif %}"
            data-refresh-mode="{{ 'disabled' if request.url.path == '/projects' else 'auto' }}"
        >
            <div class="sync-status-head">
                <div class="sync-status-title">
                    <span class="sync-dot" id="syncStatusDot"></span>
                    <span id="syncStatusLabel">연결 확인 중</span>
                </div>
                <span class="sync-pill" id="syncSessionPill">세션 준비 중</span>
            </div>
            <div class="sync-meta">
                <div>마지막 확인: <strong id="syncLastChecked">-</strong></div>
                <div>서버 시간: <strong id="syncServerTime">{{ server_time or '-' }}</strong></div>
                <div>데이터 버전: <strong id="syncDataVersion">{{ data_version or '-' }}</strong></div>
                <div>계약/청구 동기화: <strong>{{ import_sync_summary.contract_project_count or 0 }}</strong> / <strong>{{ import_sync_summary.billing_project_count or 0 }}</strong></div>
            </div>
        </aside>
    </nav>

    {% if message %}
        <div class="message">{{ message }}</div>
    {% endif %}

    {% block content %}{% endblock %}
</div>
{% block script %}{% endblock %}
<script>
    (() => {
        const widget = document.getElementById("syncStatusWidget");
        if (!widget) return;

        const dot = document.getElementById("syncStatusDot");
        const label = document.getElementById("syncStatusLabel");
        const sessionPill = document.getElementById("syncSessionPill");
        const lastChecked = document.getElementById("syncLastChecked");
        const serverTime = document.getElementById("syncServerTime");
        const dataVersion = document.getElementById("syncDataVersion");
        let pageVersion = widget.dataset.dataVersion || "";
        const refreshUrl = widget.dataset.refreshUrl || window.location.href;
        const refreshMode = widget.dataset.refreshMode || "auto";
        let refreshInFlight = false;
        let pendingVersion = "";
        let isFormDirty = false;

        function getSessionId() {
            const key = "intranet-client-session-id";
            let sessionId = window.localStorage.getItem(key);
            if (!sessionId) {
                sessionId = `session-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
                window.localStorage.setItem(key, sessionId);
            }
            return sessionId;
        }

        const clientSessionId = getSessionId();
        window.clientSessionId = clientSessionId;
        sessionPill.textContent = clientSessionId;

        function updateWidgetTitle() {
            widget.title = [
                `상태: ${label.textContent}`,
                `세션: ${sessionPill.textContent}`,
                `마지막 확인: ${lastChecked.textContent}`,
                `서버 시간: ${serverTime.textContent}`,
                `데이터 버전: ${dataVersion.textContent}`,
            ].join("\n");
        }

        function prepareCollabForms() {
            document.querySelectorAll("form[data-collab-form]").forEach((form) => {
                let sessionInput = form.querySelector('input[name="client_session_id"]');
                if (!sessionInput) {
                    sessionInput = document.createElement("input");
                    sessionInput.type = "hidden";
                    sessionInput.name = "client_session_id";
                    form.appendChild(sessionInput);
                }
                sessionInput.value = clientSessionId;

                let submittedInput = form.querySelector('input[name="client_submitted_at"]');
                if (!submittedInput) {
                    submittedInput = document.createElement("input");
                    submittedInput.type = "hidden";
                    submittedInput.name = "client_submitted_at";
                    form.appendChild(submittedInput);
                }

                const markDirty = () => {
                    isFormDirty = true;
                };

                form.addEventListener("input", markDirty);
                form.addEventListener("change", markDirty);
                form.addEventListener("submit", () => {
                    isFormDirty = false;
                    submittedInput.value = new Date().toISOString();
                });
            });
        }

        prepareCollabForms();

        function setStatus(kind, text) {
            dot.classList.remove("online", "error");
            if (kind === "online") dot.classList.add("online");
            if (kind === "error") dot.classList.add("error");
            label.textContent = text;
            lastChecked.textContent = new Date().toLocaleTimeString("ko-KR", { hour12: false });
            updateWidgetTitle();
        }

        function setPageDataVersion(nextVersion) {
            pageVersion = nextVersion || "";
            pendingVersion = "";
            widget.dataset.dataVersion = pageVersion;
            dataVersion.textContent = pageVersion || "-";
            updateWidgetTitle();
        }

        window.__setPageDataVersion = setPageDataVersion;

        function hasActiveEditor() {
            const active = document.activeElement;
            return Boolean(active && active.closest && active.closest("form[data-collab-form]"));
        }

        function hasOpenModal() {
            return Boolean(document.querySelector(".modal-backdrop.open"));
        }

        function shouldDelayRefresh() {
            return isFormDirty || hasActiveEditor() || hasOpenModal() || window.__suspendAutoRefresh === true;
        }

        async function refreshPageWhenSafe(nextVersion) {
            if (refreshInFlight) return;
            if (refreshMode === "disabled") {
                setPageDataVersion(nextVersion || pageVersion);
                setStatus("online", "서버 정상 연결");
                return;
            }
            if (shouldDelayRefresh()) {
                pendingVersion = nextVersion || pendingVersion || pageVersion;
                setStatus("online", "새 데이터 대기 중");
                return;
            }

            refreshInFlight = true;
            pendingVersion = nextVersion || pendingVersion || "";
            setStatus("online", "새 데이터 반영 중");

            try {
                window.location.replace(refreshUrl);
            } catch (error) {
                refreshInFlight = false;
                setStatus("error", "업데이트 재시도 중");
            }
        }

        async function pollHealth() {
            try {
                const response = await fetch(`/health?ts=${Date.now()}`, { cache: "no-store" });
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                const payload = await response.json();
                serverTime.textContent = payload.server_time || "-";
                dataVersion.textContent = payload.data_version || "-";
                updateWidgetTitle();
                if (payload.data_version && payload.data_version !== pageVersion) {
                    pendingVersion = payload.data_version;
                    await refreshPageWhenSafe(payload.data_version);
                    return;
                }
                if (pendingVersion && pendingVersion !== pageVersion) {
                    await refreshPageWhenSafe(pendingVersion);
                    return;
                }
                setStatus("online", "서버 정상 연결");
            } catch (error) {
                setStatus("error", "연결 오류");
            }
        }

        pollHealth();
        updateWidgetTitle();
        document.addEventListener("visibilitychange", () => {
            if (!document.hidden) {
                pollHealth();
            }
        });
        window.setInterval(pollHealth, 15000);
    })();
</script>
</body>
</html>
