/**
 * AccountingGraphSection.js
 * گراف حسابداری — نمودار شبکه‌ای حساب‌ها و جریان‌های مالی
 * SVG force-directed, بدون کتابخانه خارجی
 */

import SectionBase from "../SectionBase.js";

const TYPE_COLOR = {
    asset:     '#3b82f6',
    liability: '#f59e0b',
    equity:    '#8b5cf6',
    revenue:   '#10b981',
    expense:   '#ef4444',
    contra:    '#64748b',
};

const TYPE_LABEL = {
    asset:     'دارایی',
    liability: 'بدهی',
    equity:    'حقوق صاحبان',
    revenue:   'درآمد',
    expense:   'هزینه',
    contra:    'کنترایی',
};

/* ── Force-directed layout ────────────────────────────────── */
class ForceLayout {
    constructor(nodes, edges, W, H) {
        this.W = W; this.H = H;
        // seed positions by type cluster
        const TYPE_POS = {
            asset:     { x: W * 0.25, y: H * 0.45 },
            liability: { x: W * 0.75, y: H * 0.35 },
            equity:    { x: W * 0.75, y: H * 0.65 },
            revenue:   { x: W * 0.50, y: H * 0.15 },
            expense:   { x: W * 0.50, y: H * 0.80 },
            contra:    { x: W * 0.50, y: H * 0.50 },
        };
        this.nodes = nodes.map(n => {
            const seed = TYPE_POS[n.type] ?? { x: W/2, y: H/2 };
            return {
                ...n,
                x:  seed.x + (Math.random() - 0.5) * 180,
                y:  seed.y + (Math.random() - 0.5) * 180,
                vx: 0, vy: 0,
            };
        });
        this.edges  = edges;
        this.nodeMap = {};
        this.nodes.forEach(n => { this.nodeMap[n.id] = n; });
    }

    tick() {
        const REPEL  = 4500;
        const SPRING = 140;
        const GRAV   = 0.012;
        const DAMP   = 0.82;

        // reset forces
        this.nodes.forEach(n => { n.fx = 0; n.fy = 0; });

        // repulsion between all pairs
        for (let i = 0; i < this.nodes.length; i++) {
            for (let j = i + 1; j < this.nodes.length; j++) {
                const a = this.nodes[i], b = this.nodes[j];
                const dx = b.x - a.x, dy = b.y - a.y;
                const d2 = dx*dx + dy*dy + 0.01;
                const f  = REPEL / d2;
                const d  = Math.sqrt(d2);
                a.fx -= f * dx / d; a.fy -= f * dy / d;
                b.fx += f * dx / d; b.fy += f * dy / d;
            }
        }

        // spring attraction along edges
        this.edges.forEach(e => {
            const a = this.nodeMap[e.from], b = this.nodeMap[e.to];
            if (!a || !b) return;
            const dx = b.x - a.x, dy = b.y - a.y;
            const d  = Math.sqrt(dx*dx + dy*dy) + 0.01;
            const f  = (d - SPRING) * 0.08;
            a.fx += f * dx/d; a.fy += f * dy/d;
            b.fx -= f * dx/d; b.fy -= f * dy/d;
        });

        // integrate + gravity toward center
        const cx = this.W / 2, cy = this.H / 2;
        this.nodes.forEach(n => {
            n.vx = (n.vx + n.fx) * DAMP - (n.x - cx) * GRAV;
            n.vy = (n.vy + n.fy) * DAMP - (n.y - cy) * GRAV;
            n.x  = Math.max(50, Math.min(this.W - 50, n.x + n.vx));
            n.y  = Math.max(40, Math.min(this.H - 40, n.y + n.vy));
        });
    }

    run(n = 180) {
        for (let i = 0; i < n; i++) this.tick();
    }
}

/* ── Section ──────────────────────────────────────────────── */
export default class AccountingGraphSection extends SectionBase {

    constructor(props = {}) {
        super(props);
        this._mode    = 'template';  // 'template' | 'flow'
        this._data    = null;
        this._tooltip = null;
    }

    async template() {
        return `
        <div class="acc-graph-wrap" data-ref="wrap">
            <div class="acc-graph-toolbar">
                <div class="acc-graph-mode-toggle">
                    <button class="acc-graph-mode-btn acc-graph-mode-btn--active" data-mode="template">
                        📐 روابط Template
                    </button>
                    <button class="acc-graph-mode-btn" data-mode="flow">
                        💸 جریان‌های واقعی
                    </button>
                </div>
                <div class="acc-graph-legend" data-ref="legend"></div>
                <button class="acc-btn acc-btn--secondary acc-btn--sm" data-ref="reloadBtn">🔄 بارگذاری مجدد</button>
            </div>
            <div class="acc-graph-canvas" data-ref="canvas"></div>
            <div class="acc-graph-info" data-ref="info"></div>
        </div>`;
    }

    async afterRender() {
        this._buildLegend();
        this.ref('wrap').querySelectorAll('.acc-graph-mode-btn').forEach(btn => {
            this.on(btn, 'click', () => {
                this._mode = btn.dataset.mode;
                this.ref('wrap').querySelectorAll('.acc-graph-mode-btn').forEach(b =>
                    b.classList.toggle('acc-graph-mode-btn--active', b.dataset.mode === this._mode)
                );
                if (this._data) this._draw();
            });
        });
        this.on(this.ref('reloadBtn'), 'click', () => this._load());
        await this._load();
    }

    _buildLegend() {
        this.ref('legend').innerHTML = Object.entries(TYPE_LABEL).map(([k, v]) =>
            `<span class="acc-graph-legend-dot" style="background:${TYPE_COLOR[k]}"></span><span>${v}</span>`
        ).join('');
    }

    async _load() {
        const canvas = this.ref('canvas');
        canvas.innerHTML = `<div class="acc-graph-loading"><div class="acc-spinner"></div><span>در حال محاسبه گراف...</span></div>`;
        this.ref('info').textContent = '';
        try {
            const res  = await this.api.get('/accounting/graph');
            this._data = res;
            this._draw();
        } catch (err) {
            canvas.innerHTML = `<div class="acc-empty">خطا در بارگذاری گراف: ${this.escape(err?.message ?? '')}</div>`;
        }
    }

    _draw() {
        const canvas = this.ref('canvas');
        const W = canvas.clientWidth  || 900;
        const H = canvas.clientHeight || 560;

        const { nodes, template_edges, flow_edges } = this._data;

        // فیلتر نودهای مرتبط
        const rawEdges = this._mode === 'template' ? template_edges : flow_edges;
        const usedIds  = new Set();
        rawEdges.forEach(e => { usedIds.add(String(e.from)); usedIds.add(String(e.to)); });

        const activeNodes = nodes.filter(n => usedIds.has(String(n.id)));
        if (!activeNodes.length) {
            canvas.innerHTML = `<div class="acc-empty">
                ${this._mode === 'template'
                    ? 'هیچ Template فعالی با pair تعریف‌شده یافت نشد.'
                    : 'هیچ جریان تأییدشده‌ای یافت نشد. ابتدا سندها را تأیید کنید.'}
            </div>`;
            return;
        }

        // اجرای layout
        const layout = new ForceLayout(activeNodes, rawEdges, W, H);
        layout.run(200);

        const posMap = {};
        layout.nodes.forEach(n => { posMap[n.id] = n; });

        // build SVG
        const NS  = 'http://www.w3.org/2000/svg';
        const svg = document.createElementNS(NS, 'svg');
        svg.setAttribute('width',  W);
        svg.setAttribute('height', H);
        svg.setAttribute('viewBox', `0 0 ${W} ${H}`);
        svg.style.cssText = 'display:block;width:100%;height:100%;';

        // دستیار ساخت المان SVG
        const el = (tag, attrs) => {
            const e = document.createElementNS(NS, tag);
            Object.entries(attrs).forEach(([k, v]) => e.setAttribute(k, v));
            return e;
        };

        // arrowhead marker
        const defs   = el('defs', {});
        const marker = el('marker', { id:'arrowhead', markerWidth:'8', markerHeight:'6', refX:'8', refY:'3', orient:'auto' });
        marker.appendChild(el('polygon', { points:'0 0, 8 3, 0 6', fill:'#94a3b8' }));
        defs.appendChild(marker);
        svg.appendChild(defs);

        // یال‌ها
        const maxAmt = rawEdges.length
            ? Math.max(...rawEdges.map(e => parseFloat(e.total_amount ?? e.count ?? 1)))
            : 1;

        rawEdges.forEach(e => {
            const a = posMap[e.from], b = posMap[e.to];
            if (!a || !b) return;

            const R   = 26;
            const dx  = b.x - a.x, dy = b.y - a.y;
            const len = Math.sqrt(dx*dx + dy*dy) || 1;
            // Shorten to node edge
            const x1  = a.x + dx/len*R, y1  = a.y + dy/len*R;
            const x2  = b.x - dx/len*(R+8), y2 = b.y - dy/len*(R+8);
            // Slight curve
            const cx1 = (x1+x2)/2 - dy/len*25;
            const cy1 = (y1+y2)/2 + dx/len*25;

            const weight = this._mode === 'flow'
                ? Math.max(1, Math.round((parseFloat(e.total_amount) / maxAmt) * 5))
                : Math.max(1, Math.min(4, e.count ?? 1));

            const path = el('path', {
                d:              `M${x1},${y1} Q${cx1},${cy1} ${x2},${y2}`,
                stroke:         '#94a3b8',
                'stroke-width': weight,
                fill:           'none',
                'marker-end':   'url(#arrowhead)',
                opacity:        '0.75',
                'stroke-dasharray': this._mode === 'template' ? '5 3' : 'none',
            });

            // tooltip روی یال
            path.style.cursor = 'pointer';
            const label = this._mode === 'flow'
                ? `${(e.total_amount / 1).toLocaleString('fa-IR')} | ${e.flow_count} تراکنش`
                : (e.labels ?? []).filter((v,i,a)=>a.indexOf(v)===i).join(' / ');

            path.addEventListener('mouseover', ev => this._showTip(ev, label));
            path.addEventListener('mousemove', ev => this._moveTip(ev));
            path.addEventListener('mouseout',  () => this._hideTip());
            svg.appendChild(path);
        });

        // نودها
        layout.nodes.forEach(n => {
            const g     = el('g', { transform:`translate(${n.x},${n.y})`, cursor:'pointer' });
            const color = TYPE_COLOR[n.type] || '#64748b';
            const hasFlow = (n.total_in + n.total_out) > 0;

            g.appendChild(el('circle', {
                r: hasFlow ? 28 : 22,
                fill:         color,
                opacity:      '0.18',
                stroke:       color,
                'stroke-width': '2',
            }));
            g.appendChild(el('circle', {
                r:    hasFlow ? 18 : 14,
                fill: color,
            }));

            // کد حساب
            const codeText = el('text', {
                'text-anchor':     'middle',
                'dominant-baseline': 'middle',
                fill:              '#fff',
                'font-size':       '9',
                'font-weight':     '700',
            });
            codeText.textContent = n.code ?? '';
            g.appendChild(codeText);

            // نام حساب
            const nameText = el('text', {
                'text-anchor':     'middle',
                'dominant-baseline': 'hanging',
                y:                 hasFlow ? 30 : 24,
                fill:              '#1e293b',
                'font-size':       '10',
                'font-weight':     '600',
            });
            nameText.textContent = n.name?.length > 14 ? n.name.slice(0,13) + '…' : (n.name ?? '');
            g.appendChild(nameText);

            // tooltip نود
            const tipText = `${n.name} (${TYPE_LABEL[n.type] ?? n.type})` +
                (hasFlow ? `\nورودی: ${Number(n.total_in).toLocaleString('fa-IR')}\nخروجی: ${Number(n.total_out).toLocaleString('fa-IR')}` : '');

            g.addEventListener('mouseover', ev => this._showTip(ev, tipText));
            g.addEventListener('mousemove', ev => this._moveTip(ev));
            g.addEventListener('mouseout',  () => this._hideTip());
            svg.appendChild(g);
        });

        canvas.innerHTML = '';
        canvas.appendChild(svg);

        const edgeCnt = rawEdges.length, nodeCnt = layout.nodes.length;
        this.ref('info').textContent =
            `${nodeCnt} حساب | ${edgeCnt} رابطه${this._mode === 'flow' ? ' (تأییدشده)' : ' (Template)'}`;
    }

    /* ── Tooltip ──────────────────────────────────────────────── */
    _showTip(ev, text) {
        if (!this._tooltip) {
            this._tooltip = document.createElement('div');
            this._tooltip.className = 'acc-graph-tooltip';
            document.body.appendChild(this._tooltip);
        }
        this._tooltip.style.display = 'block';
        this._tooltip.textContent   = text;
        this._moveTip(ev);
    }

    _moveTip(ev) {
        if (!this._tooltip) return;
        this._tooltip.style.left = (ev.clientX + 14) + 'px';
        this._tooltip.style.top  = (ev.clientY - 10) + 'px';
    }

    _hideTip() {
        if (this._tooltip) this._tooltip.style.display = 'none';
    }

    destroy() {
        this._hideTip();
        if (this._tooltip) { this._tooltip.remove(); this._tooltip = null; }
        super.destroy();
    }
}
