/**
 * Animal Profile — Plataforma Ganadera
 * Perfil/Expediente completo del animal con tabs, timeline, charts
 */

$(document).ready(function() {
    AnimalProfile.init();
});

const AnimalProfile = {
    animalId: null,
    data: null,
    charts: {},

    async init() {
        this.animalId = $('#animalProfile').data('animal-id');
        if (!this.animalId) return;

        this.bindEvents();
        await this.loadProfile();
    },

    // ─── LOAD PROFILE ───────────────────────────────────────

    async loadProfile() {
        const res = await API.get(`/animals/${this.animalId}/profile`);
        if (!res.success) {
            Toast.error('Error cargando perfil del animal');
            return;
        }

        this.data = res.data;
        this.renderHero();
        this.renderKPIs();
        this.renderAlerts();
        this.renderSummary();
    },

    // ─── HERO ───────────────────────────────────────────────

    renderHero() {
        const a = this.data.animal;

        // Photo — field from DB is primary_photo, ensure absolute path with /
        const mainPhoto = a.primary_photo || a.main_photo;
        if (mainPhoto) {
            const photoUrl = mainPhoto.startsWith('/') ? mainPhoto : '/' + mainPhoto;
            $('#profilePhoto').html(`<img src="${photoUrl}" alt="${a.name || ''}">`);
            $('#heroBg').css('background-image', `linear-gradient(to right, rgba(22,25,32,.95), rgba(22,25,32,.7)), url(${photoUrl})`);
            $('#heroBg').css('background-size', 'cover');
        }

        // Name & ID
        const sexIcon = a.sex === 'male' ? '<span class="sex-male">♂</span> ' : '<span class="sex-female">♀</span> ';
        $('#animalName').html(sexIcon + (a.name || 'Sin nombre'));
        $('#animalIdentifier').text(a.tag_id || a.identifier || '#' + a.id);

        // Species icon
        const speciesIcons = { 'Caprinos': '🐐', 'Bovinos': '🐄', 'Porcinos': '🐷', 'Aves': '🐔', 'Ovinos': '🐑', 'Equinos': '🐴' };
        const sIcon = speciesIcons[a.species_name] || '🐾';
        $('#profileSpeciesIcon').text(sIcon);

        // Chips
        const $chips = $('#profileChips');
        $chips.empty();
        if (a.species_name) $chips.append(`<span class="chip chip-species">${sIcon} ${a.species_name}</span>`);
        if (a.breed_name) $chips.append(`<span class="chip chip-outline">${a.breed_name}</span>`);
        if (a.lot_name) $chips.append(`<span class="chip chip-accent">${a.lot_name}</span>`);
        $chips.append(this.getStatusChip(a.status));
        $chips.append(this.getHealthChip(a.health_status));
        if (a.reproductive_status) {
            const reproLabel = this.getReproductiveLabel(a.reproductive_status);
            if (reproLabel) {
                $chips.append(`<span class="chip chip-repro">${reproLabel}</span>`);
            }
        }

        // Edit button
        $('#btnEditAnimal').attr('href', `/animales/${a.id}/editar`);
    },

    // ─── KPIs ───────────────────────────────────────────────

    renderKPIs() {
        const a = this.data.animal;
        const p = this.data;

        // Age
        if (a.birth_date) {
            $('#kpiAge').text(this.calcAge(a.birth_date));
        }

        // Weight
        if (a.current_weight) {
            $('#kpiWeight').text(parseFloat(a.current_weight).toFixed(1) + ' kg');
        }

        // Vaccines count
        const vaxCount = p.vaccinations?.length || 0;
        $('#kpiVaccines').text(vaxCount);

        // Offspring
        const offCount = p.offspring?.length || 0;
        $('#kpiOffspring').text(offCount);

        // Total events
        const evCount = (p.health_events?.length || 0)
            + vaxCount
            + (p.weights?.length || 0)
            + (p.reproduction?.length || 0)
            + (p.movements?.length || 0);
        $('#kpiEvents').text(evCount);
    },

    // ─── ALERTS ─────────────────────────────────────────────

    renderAlerts() {
        const a = this.data.animal;
        const $alerts = $('#profileAlerts');
        $alerts.empty();

        const alerts = [];

        if (a.health_status === 'sick') {
            alerts.push({ type: 'danger', text: 'Animal marcado como ENFERMO. Requiere atención veterinaria.' });
        }
        if (a.health_status === 'quarantine') {
            alerts.push({ type: 'warning', text: 'Animal en CUARENTENA.' });
        }

        // Pending vaccines
        const pending = this.data.vaccinations?.filter(v => v.status === 'pending') || [];
        if (pending.length) {
            alerts.push({ type: 'warning', text: `${pending.length} vacuna(s) pendiente(s) de aplicar.` });
        }

        if (!alerts.length) {
            $alerts.hide();
            return;
        }

        alerts.forEach(al => {
            $alerts.append(`
                <div class="profile-alert profile-alert-${al.type}">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
                        <line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>
                    </svg>
                    ${al.text}
                </div>
            `);
        });
        $alerts.show();
    },

    // ─── SUMMARY TAB ────────────────────────────────────────

    renderSummary() {
        const a = this.data.animal;

        const rows = [
            ['ID', '#' + a.id],
            ['Nombre', a.name || '—'],
            ['Arete', a.tag_id || '—'],
            ['Especie', a.species_name || '—'],
            ['Raza', a.breed_name || '—'],
            ['Sexo', a.sex === 'male' ? 'Macho' : 'Hembra'],
            ['Color', a.color || '—'],
            ['Fecha nacimiento', App.formatDate(a.birth_date)],
            ['Edad', a.birth_date ? this.calcAge(a.birth_date) : '—'],
            ['Madre', a.mother_name ? `<a href="/animales/${a.mother_id}">${a.mother_name}</a>` : '—'],
            ['Padre', a.father_name ? `<a href="/animales/${a.father_id}">${a.father_name}</a>` : '—'],
            ['Peso actual', a.current_weight ? a.current_weight + ' kg' : '—'],
            ['Lote', a.lot_name || '—'],
            ['Corral', a.enclosure_name || '—'],
            ['Estado', a.status || '—'],
            ['Estado sanitario', a.health_status || '—'],
            ['Estado reproductivo', a.reproductive_status || '—'],
            ['Observaciones', a.notes || '—'],
        ];

        let html = '';
        rows.forEach(([label, value]) => {
            html += `<div class="detail-row"><span class="detail-label">${label}</span><span class="detail-value">${value}</span></div>`;
        });
        $('#summaryGeneral').html(html);

        // Recent events summary
        this.renderRecentEvents();
    },

    renderRecentEvents() {
        const events = this.buildTimeline().slice(0, 5);
        const $container = $('#summaryEvents');

        if (!events.length) {
            $container.html('<div class="empty-state-sm">Sin eventos registrados</div>');
            return;
        }

        let html = '<div class="timeline">';
        events.forEach(ev => {
            html += `
                <div class="timeline-item">
                    <div class="timeline-dot timeline-dot-${ev.type}"></div>
                    <div class="timeline-date">${App.formatDateTime(ev.date)}</div>
                    <div class="timeline-title">${ev.title}</div>
                    <div class="timeline-desc">${ev.description || ''}</div>
                </div>
            `;
        });
        html += '</div>';
        $container.html(html);
    },

    // ─── TAB: HEALTH ────────────────────────────────────────

    async loadHealth() {
        const events = this.data.health_events || [];
        const $container = $('#healthList');

        if (!events.length) {
            $container.html('<div class="empty-state-sm">Sin eventos de salud registrados</div>');
            return;
        }

        let html = '<div class="timeline">';
        events.forEach(ev => {
            html += `
                <div class="timeline-item">
                    <div class="timeline-dot timeline-dot-health"></div>
                    <div class="timeline-date">${App.formatDate(ev.event_date)}</div>
                    <div class="timeline-title">${ev.event_type}: ${ev.diagnosis || ev.description || ''}</div>
                    <div class="timeline-desc">${ev.treatment || ''} ${ev.notes ? '— ' + ev.notes : ''}</div>
                </div>
            `;
        });
        html += '</div>';
        $container.html(html);
    },

    // ─── TAB: VACCINES ──────────────────────────────────────

    async loadVaccines() {
        const vaccines = this.data.vaccinations || [];
        const $container = $('#vaccinesList');

        if (!vaccines.length) {
            $container.html('<div class="empty-state-sm">Sin vacunas registradas</div>');
            return;
        }

        let html = '<table class="data-table"><thead><tr><th>Vacuna</th><th>Fecha</th><th>Dosis</th><th>Lote</th><th>Próx. Refuerzo</th><th>Estado</th></tr></thead><tbody>';
        vaccines.forEach(v => {
            const statusCls = v.status === 'applied' ? 'chip-success' : v.status === 'pending' ? 'chip-warning' : '';
            html += `
                <tr>
                    <td><strong>${v.vaccine_name || ''}</strong></td>
                    <td>${App.formatDate(v.application_date)}</td>
                    <td>${v.dose || '—'}</td>
                    <td>${v.batch_number || '—'}</td>
                    <td>${App.formatDate(v.next_dose_date)}</td>
                    <td><span class="chip chip-sm ${statusCls}">${v.status || ''}</span></td>
                </tr>
            `;
        });
        html += '</tbody></table>';
        $container.html(html);
    },

    // ─── TAB: WEIGHTS ───────────────────────────────────────

    async loadWeights() {
        const weights = this.data.weights || [];
        const $list = $('#weightsList');

        if (!weights.length) {
            $list.html('<div class="empty-state-sm">Sin registros de peso</div>');
            return;
        }

        // Chart
        const ctx = document.getElementById('weightChart');
        if (ctx && weights.length > 1) {
            const sorted = [...weights].sort((a, b) => new Date(a.weigh_date) - new Date(b.weigh_date));
            this.charts.weight = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: sorted.map(w => App.formatDate(w.weigh_date)),
                    datasets: [{
                        label: 'Peso (kg)',
                        data: sorted.map(w => parseFloat(w.weight)),
                        borderColor: '#047857',
                        backgroundColor: 'rgba(4,120,87,.1)',
                        fill: true,
                        tension: .3,
                        pointBackgroundColor: '#047857',
                        pointRadius: 4,
                        pointHoverRadius: 6,
                    }],
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: { legend: { display: false } },
                    scales: {
                        x: { grid: { display: false }, ticks: { color: '#64748B', font: { size: 11 } } },
                        y: { grid: { color: 'rgba(0,0,0,.06)' }, ticks: { color: '#64748B', font: { size: 11 } } },
                    },
                    animation: { duration: 800, easing: 'easeOutQuart' },
                },
            });
        }

        // Table
        let html = '<table class="data-table"><thead><tr><th>Fecha</th><th>Peso</th><th>Ganancia</th><th>Notas</th></tr></thead><tbody>';
        const sorted = [...weights].sort((a, b) => new Date(b.weigh_date) - new Date(a.weigh_date));
        sorted.forEach((w, i) => {
            const gain = i < sorted.length - 1
                ? (parseFloat(w.weight) - parseFloat(sorted[i + 1].weight)).toFixed(1)
                : '—';
            const gainClass = parseFloat(gain) > 0 ? 'color:#27ae60' : parseFloat(gain) < 0 ? 'color:#c0392b' : '';
            html += `
                <tr>
                    <td>${App.formatDate(w.weigh_date)}</td>
                    <td><strong>${parseFloat(w.weight).toFixed(1)} kg</strong></td>
                    <td style="${gainClass}">${gain !== '—' ? (parseFloat(gain) > 0 ? '+' : '') + gain + ' kg' : '—'}</td>
                    <td>${w.notes || '—'}</td>
                </tr>
            `;
        });
        html += '</tbody></table>';
        $list.html(html);
    },

    // ─── TAB: REPRODUCTION ──────────────────────────────────

    async loadReproduction() {
        const events = this.data.reproduction || [];
        const $container = $('#reproductionList');

        if (!events.length) {
            $container.html('<div class="empty-state-sm">Sin eventos reproductivos</div>');
            return;
        }

        let html = '<div class="timeline">';
        events.forEach(ev => {
            html += `
                <div class="timeline-item">
                    <div class="timeline-dot timeline-dot-repro"></div>
                    <div class="timeline-date">${App.formatDate(ev.event_date)}</div>
                    <div class="timeline-title">${ev.event_type || ''}</div>
                    <div class="timeline-desc">${ev.notes || ''}</div>
                </div>
            `;
        });
        html += '</div>';
        $container.html(html);
    },

    // ─── TAB: GENEALOGY ─────────────────────────────────────

    async loadGenealogy() {
        const a = this.data.animal;
        const offspring = this.data.offspring || [];
        const $container = $('#genealogyTree');

        let html = '<div class="genealogy-tree">';

        // ── Parents section ──
        html += '<div class="gen-section-title">🧬 Padres</div>';
        html += '<div class="gen-row gen-parents">';
        html += this.genCard(a.father_id, a.father_name, a.father_tag, 'Padre', 'male');
        html += this.genCard(a.mother_id, a.mother_name, a.mother_tag, 'Madre', 'female');
        html += '</div>';

        // ── Connector ──
        html += '<div class="gen-connector"></div>';

        // ── Current animal ──
        html += '<div class="gen-row gen-current">';
        const speciesIcons = { 'Caprinos': '🐐', 'Bovinos': '🐄', 'Porcinos': '🐷', 'Aves': '🐔', 'Ovinos': '🐑', 'Equinos': '🐴' };
        const sIcon = speciesIcons[a.species_name] || '🐾';
        html += `<div class="gen-card gen-self">
                    <span class="gen-role">Este animal</span>
                    <strong>${a.sex === 'male' ? '♂' : '♀'} ${a.name || a.tag_id || '#' + a.id}</strong>
                    <span class="gen-meta">${sIcon} ${a.species_name || ''} ${a.breed_name ? '· ' + a.breed_name : ''}</span>
                    ${a.tag_id ? `<span class="gen-tag">${a.tag_id}</span>` : ''}
                 </div>`;
        html += '</div>';

        // ── Offspring section ──
        if (offspring.length) {
            html += '<div class="gen-connector"></div>';
            html += `<div class="gen-section-title">🐣 Crías (${offspring.length})</div>`;
            html += '<div class="gen-row gen-offspring">';
            offspring.forEach(o => {
                const age = o.birth_date ? this.calcAge(o.birth_date) : '';
                const statusBadge = o.status === 'active'
                    ? '<span style="color:#16a34a;font-size:.68rem">● Activo</span>'
                    : o.status === 'sold'
                    ? '<span style="color:#3b82f6;font-size:.68rem">● Vendido</span>'
                    : o.status === 'dead'
                    ? '<span style="color:#ef4444;font-size:.68rem">● Muerto</span>'
                    : `<span style="font-size:.68rem;color:var(--text-muted)">● ${o.status || ''}</span>`;
                html += `<a class="gen-card" href="/animales/${o.id}">
                    <span class="gen-role">Cría</span>
                    <strong>${o.sex === 'male' ? '♂' : '♀'} ${o.name || o.tag_id || '#' + o.id}</strong>
                    ${o.tag_id ? `<span class="gen-tag">${o.tag_id}</span>` : ''}
                    <span class="gen-meta">${age}${age && o.species_name ? ' · ' : ''}${o.species_name || ''}</span>
                    ${statusBadge}
                </a>`;
            });
            html += '</div>';
        } else {
            html += '<div class="gen-connector"></div>';
            html += '<div class="gen-section-title">🐣 Crías</div>';
            html += '<div style="text-align:center;padding:16px;color:var(--text-muted);font-size:.85rem">Sin crías registradas</div>';
        }

        html += '</div>';
        $container.html(html);
    },

    genCard(id, name, tag, role, sex) {
        if (!id) {
            return `<div class="gen-card gen-empty"><span class="gen-role">${role}</span><span>No registrado</span></div>`;
        }
        const sexIcon = sex === 'male' ? '♂' : sex === 'female' ? '♀' : '';
        return `<a class="gen-card" href="/animales/${id}">
                    <span class="gen-role">${role}</span>
                    <strong>${sexIcon} ${name || '#' + id}</strong>
                    ${tag ? `<span class="gen-tag">${tag}</span>` : ''}
                </a>`;
    },

    // ─── TAB: PHOTOS ────────────────────────────────────────

    async loadPhotos() {
        // Fetch fresh photos from API
        try {
            const res = await API.get(`/animals/${this.animalId}/photos`);
            if (res.success) {
                this.data.photos = res.data;
            }
        } catch(e) { /* use cached */ }

        const photos = this.data.photos || [];
        const $gallery = $('#photoGallery');

        if (!photos.length) {
            $gallery.html(`
                <div class=\"empty-state-sm\" style=\"text-align:center;padding:40px 20px\">
                    <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" style=\"color:var(--text-muted);margin-bottom:12px\">
                        <path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\"/>
                        <circle cx=\"12\" cy=\"13\" r=\"4\"/>
                    </svg>
                    <p style=\"margin:0 0 4px;font-weight:600\">Sin fotos</p>
                    <p style=\"margin:0;font-size:.85rem;color:var(--text-muted)\">Sube la primera foto de este animal</p>
                </div>
            `);
            return;
        }

        const contextLabels = {
            profile: '📷 Perfil', birth: '🐣 Nacimiento', health: '🏥 Salud',
            treatment: '💊 Tratamiento', sale: '💰 Venta', disposal: '📋 Baja',
            task: '✅ Tarea', weight: '⚖️ Peso/Engorda', other: '📎 Otro'
        };

        // Group by context
        const grouped = {};
        photos.forEach(p => {
            const ctx = p.context || 'other';
            if (!grouped[ctx]) grouped[ctx] = [];
            grouped[ctx].push(p);
        });

        let html = `<div class=\"photo-gallery-stats\">${photos.length} foto${photos.length !== 1 ? 's' : ''}</div>`;

        // Photos grid — all photos together with context badge
        html += '<div class=\"photo-grid\">';
        photos.forEach((p, index) => {
            const thumb = p.thumbnail_path || p.file_path;
            const isPrimary = p.is_primary == 1;
            const ctx = p.context || 'other';
            const label = contextLabels[ctx] || ctx;
            const caption = p.caption ? `<div class=\"photo-grid-caption\">${p.caption}</div>` : '';
            const date = p.taken_at || p.created_at;

            html += `
                <div class=\"photo-grid-item ${isPrimary ? 'photo-primary' : ''}\" data-photo-id=\"${p.id}\" data-index=\"${index}\">
                    <img src=\"/${thumb}\" alt=\"${p.caption || ''}\" loading=\"lazy\" onclick=\"AnimalProfile.openLightbox(${index})\">
                    <div class=\"photo-grid-overlay\">
                        <span class=\"photo-ctx-badge photo-ctx-${ctx}\">${label}</span>
                        ${isPrimary ? '<span class=\"photo-star\">★ Principal</span>' : ''}
                    </div>
                    ${caption}
                    <div class=\"photo-grid-date\">${date ? App.formatDate(date) : ''}</div>
                    <div class=\"photo-grid-actions\">
                        ${!isPrimary ? `<button class=\"btn-icon-xs\" onclick=\"AnimalProfile.setPhotoPrimary(${p.id})\" title=\"Hacer principal\">★</button>` : ''}
                        <button class=\"btn-icon-xs btn-icon-danger\" onclick=\"AnimalProfile.deletePhoto(${p.id})\" title=\"Eliminar\">✕</button>
                    </div>
                </div>
            `;
        });
        html += '</div>';

        $gallery.html(html);
    },

    openLightbox(index) {
        const photos = this.data.photos || [];
        if (!photos.length) return;

        this._lightboxIndex = index;
        const p = photos[index];
        const contextLabels = {
            profile: 'Perfil', birth: 'Nacimiento', health: 'Salud',
            treatment: 'Tratamiento', sale: 'Venta', disposal: 'Baja',
            task: 'Tarea', weight: 'Peso/Engorda', other: 'Otro'
        };

        // Remove existing lightbox
        const existing = document.getElementById('photoLightbox');
        if (existing) existing.remove();

        const lb = document.createElement('div');
        lb.id = 'photoLightbox';
        lb.className = 'lightbox-overlay';
        lb.innerHTML = `
            <div class=\"lightbox-container\">
                <button class=\"lightbox-close\" id=\"lbClose\">&times;</button>
                <button class=\"lightbox-nav lightbox-prev\" id=\"lbPrev\">&lsaquo;</button>
                <button class=\"lightbox-nav lightbox-next\" id=\"lbNext\">&rsaquo;</button>
                <div class=\"lightbox-img-wrap\">
                    <img src=\"/${p.file_path}\" alt=\"\" id=\"lbImage\">
                </div>
                <div class=\"lightbox-info\" id=\"lbInfo\">
                    <span class=\"lightbox-counter\">${index + 1} / ${photos.length}</span>
                    <span class=\"lightbox-ctx\">${contextLabels[p.context] || ''}</span>
                    ${p.caption ? `<span class=\"lightbox-caption\">${p.caption}</span>` : ''}
                    <span class=\"lightbox-date\">${p.taken_at ? App.formatDate(p.taken_at) : ''}</span>
                </div>
            </div>
        `;
        document.body.appendChild(lb);

        // Animate in
        requestAnimationFrame(() => lb.classList.add('active'));

        // Events
        document.getElementById('lbClose').onclick = () => this.closeLightbox();
        document.getElementById('lbPrev').onclick = () => this.navigateLightbox(-1);
        document.getElementById('lbNext').onclick = () => this.navigateLightbox(1);

        lb.addEventListener('click', (e) => {
            if (e.target === lb) this.closeLightbox();
        });

        // Keyboard
        this._lbKeyHandler = (e) => {
            if (e.key === 'Escape') this.closeLightbox();
            if (e.key === 'ArrowLeft') this.navigateLightbox(-1);
            if (e.key === 'ArrowRight') this.navigateLightbox(1);
        };
        document.addEventListener('keydown', this._lbKeyHandler);
    },

    navigateLightbox(dir) {
        const photos = this.data.photos || [];
        if (!photos.length) return;
        this._lightboxIndex = (this._lightboxIndex + dir + photos.length) % photos.length;
        const p = photos[this._lightboxIndex];
        const contextLabels = {
            profile: 'Perfil', birth: 'Nacimiento', health: 'Salud',
            treatment: 'Tratamiento', sale: 'Venta', disposal: 'Baja',
            task: 'Tarea', weight: 'Peso/Engorda', other: 'Otro'
        };

        document.getElementById('lbImage').src = '/' + p.file_path;
        document.getElementById('lbInfo').innerHTML = `
            <span class=\"lightbox-counter\">${this._lightboxIndex + 1} / ${photos.length}</span>
            <span class=\"lightbox-ctx\">${contextLabels[p.context] || ''}</span>
            ${p.caption ? `<span class=\"lightbox-caption\">${p.caption}</span>` : ''}
            <span class=\"lightbox-date\">${p.taken_at ? App.formatDate(p.taken_at) : ''}</span>
        `;
    },

    closeLightbox() {
        const lb = document.getElementById('photoLightbox');
        if (lb) {
            lb.classList.remove('active');
            setTimeout(() => lb.remove(), 200);
        }
        if (this._lbKeyHandler) {
            document.removeEventListener('keydown', this._lbKeyHandler);
            this._lbKeyHandler = null;
        }
    },

    async setPhotoPrimary(photoId) {
        const res = await API.put(`/photos/${photoId}/primary`);
        if (res.success) {
            Toast.success('Foto principal actualizada');
            await this.loadProfile();
            this.loadPhotos();
        } else {
            Toast.error(res.message || 'Error');
        }
    },

    async deletePhoto(photoId) {
        const confirmed = await Modal.confirm('Eliminar foto', '¿Estás seguro de eliminar esta foto?');
        if (!confirmed) return;

        const res = await API.delete(`/photos/${photoId}`);
        if (res.success !== false) {
            Toast.success('Foto eliminada');
            this.data.photos = (this.data.photos || []).filter(p => p.id !== photoId);
            this.loadPhotos();
            // Refresh hero if we deleted primary
            await this.loadProfile();
        } else {
            Toast.error('Error al eliminar foto');
        }
    },

    // ─── TAB: MOVEMENTS ─────────────────────────────────────

    async loadMovements() {
        const moves = this.data.movements || [];
        const $container = $('#movementsList');

        if (!moves.length) {
            $container.html('<div class="empty-state-sm">Sin movimientos registrados</div>');
            return;
        }

        let html = '<div class="timeline">';
        moves.forEach(m => {
            html += `
                <div class="timeline-item">
                    <div class="timeline-dot timeline-dot-move"></div>
                    <div class="timeline-date">${App.formatDate(m.movement_date)}</div>
                    <div class="timeline-title">${m.movement_type || 'Movimiento'}</div>
                    <div class="timeline-desc">${m.from_location || '?'} → ${m.to_location || '?'} ${m.reason ? '— ' + m.reason : ''}</div>
                </div>
            `;
        });
        html += '</div>';
        $container.html(html);
    },

    // ─── TAB: TIMELINE ──────────────────────────────────────

    buildTimeline() {
        const events = [];
        const p = this.data;

        (p.health_events || []).forEach(e => {
            events.push({ date: e.event_date, type: 'health', title: `Salud: ${e.event_type}`, description: e.diagnosis || e.description });
        });
        (p.vaccinations || []).forEach(e => {
            events.push({ date: e.application_date, type: 'vaccine', title: `Vacuna: ${e.vaccine_name}`, description: `Dosis: ${e.dose || '—'}` });
        });
        (p.weights || []).forEach(e => {
            events.push({ date: e.weigh_date, type: 'weight', title: `Peso: ${e.weight} kg`, description: e.notes });
        });
        (p.reproduction || []).forEach(e => {
            events.push({ date: e.event_date, type: 'repro', title: `Reproducción: ${e.event_type}`, description: e.notes });
        });
        (p.movements || []).forEach(e => {
            events.push({ date: e.movement_date, type: 'move', title: 'Movimiento', description: `${e.from_location} → ${e.to_location}` });
        });

        events.sort((a, b) => new Date(b.date) - new Date(a.date));
        return events;
    },

    async loadTimeline() {
        const filter = $('#timelineFilter').val();
        let events = this.buildTimeline();

        if (filter) {
            const typeMap = { health: 'health', vaccine: 'vaccine', weight: 'weight', reproduction: 'repro', movement: 'move' };
            events = events.filter(e => e.type === typeMap[filter]);
        }

        const $container = $('#timelineContent');

        if (!events.length) {
            $container.html('<div class="empty-state-sm">Sin eventos para mostrar</div>');
            return;
        }

        let html = '<div class="timeline">';
        events.forEach(ev => {
            html += `
                <div class="timeline-item">
                    <div class="timeline-dot timeline-dot-${ev.type}"></div>
                    <div class="timeline-date">${App.formatDateTime(ev.date)}</div>
                    <div class="timeline-title">${ev.title}</div>
                    <div class="timeline-desc">${ev.description || ''}</div>
                </div>
            `;
        });
        html += '</div>';
        $container.html(html);
    },

    // ─── EVENTS ─────────────────────────────────────────────

    bindEvents() {
        const self = this;

        // Tab switching
        $('.tab-btn').on('click', function() {
            const tab = $(this).data('tab');
            $('.tab-btn').removeClass('active');
            $(this).addClass('active');
            $('.tab-panel').removeClass('active');
            $(`#tab-${tab}`).addClass('active');

            // Load tab content on demand
            const loaders = {
                health: () => self.loadHealth(),
                vaccines: () => self.loadVaccines(),
                weights: () => self.loadWeights(),
                reproduction: () => self.loadReproduction(),
                genealogy: () => self.loadGenealogy(),
                photos: () => self.loadPhotos(),
                documents: () => self.loadDocuments(),
                movements: () => self.loadMovements(),
                timeline: () => self.loadTimeline(),
            };
            if (loaders[tab]) loaders[tab]();
        });

        // More actions dropdown
        $('#btnMoreActions').on('click', function(e) {
            e.stopPropagation();
            $('#moreActionsMenu').toggle();
        });
        $(document).on('click', () => $('#moreActionsMenu').hide());

        // Quick actions from dropdown
        $(document).on('click', '[data-action]', function(e) {
            e.preventDefault();
            const action = $(this).data('action');
            self.handleAction(action);
        });

        // Timeline filter
        $('#timelineFilter').on('change', () => self.loadTimeline());

        // Photo upload — with context selector
        const btnUpload = document.getElementById('btnUploadPhoto');
        const btnAddPhotos = document.getElementById('btnAddPhotos');
        const photoFileInput = document.getElementById('photoFileInput');

        const triggerPhotoUpload = () => this.showPhotoUploadModal();

        if (btnUpload) btnUpload.addEventListener('click', triggerPhotoUpload);
        if (btnAddPhotos) btnAddPhotos.addEventListener('click', triggerPhotoUpload);

        if (photoFileInput) {
            photoFileInput.addEventListener('change', function() {
                if (this.files.length) {
                    self.uploadPhotosWithContext(Array.from(this.files), self._photoContext || 'profile');
                    this.value = '';
                }
            });
        }

        // Document upload
        $('#btnAddDocument').on('click', () => self.showDocumentUpload());
    },

    // ─── ACTIONS ────────────────────────────────────────────

    handleAction(action) {
        switch (action) {
            case 'weight':
                this.showWeightModal();
                break;
            case 'vaccine':
                window.location.href = `/vacunas/aplicar?animal_id=${this.animalId}`;
                break;
            case 'health':
                window.location.href = `/sanidad/registrar?animal_id=${this.animalId}`;
                break;
            case 'move':
                this.showMoveModal();
                break;
            case 'photo':
                $('#photoFileInput').click();
                break;
            case 'disposal':
                this.showDisposalModal();
                break;
        }
    },

    showWeightModal() {
        const $modal = Modal.show({
            title: 'Registrar Peso',
            body: `
                <div class="form-group">
                    <label>Peso (kg)</label>
                    <input type="number" class="form-input" id="weightInput" step="0.1" min="0" required autofocus>
                </div>
                <div class="form-group">
                    <label>Fecha</label>
                    <input type="date" class="form-input" id="weightDate" value="${new Date().toISOString().split('T')[0]}">
                </div>
                <div class="form-group">
                    <label>Notas</label>
                    <textarea class="form-input" id="weightNotes" rows="2"></textarea>
                </div>
            `,
            footer: `
                <button class="btn btn-outline modal-cancel">Cancelar</button>
                <button class="btn btn-primary" id="btnSaveWeight">Guardar</button>
            `,
        });

        $modal.find('.modal-cancel').on('click', () => Modal.close($modal));
        $modal.find('#btnSaveWeight').on('click', async () => {
            const weight = $('#weightInput').val();
            const date = $('#weightDate').val();
            const notes = $('#weightNotes').val();

            if (!weight) { Toast.warning('Ingresa el peso'); return; }

            const res = await API.post(`/animals/${this.animalId}/weights`, { weight, weigh_date: date, notes });
            if (res.success) {
                Toast.success('Peso registrado');
                Modal.close($modal);
                this.loadProfile();
            } else {
                Toast.error(res.message || 'Error al guardar');
            }
        });
    },

    showMoveModal() {
        const $modal = Modal.show({
            title: 'Mover Animal',
            body: `
                <div class="form-group">
                    <label>Destino (corral/ubicación)</label>
                    <select class="form-input" id="moveDestination"></select>
                </div>
                <div class="form-group">
                    <label>Motivo</label>
                    <input type="text" class="form-input" id="moveReason">
                </div>
            `,
            footer: `
                <button class="btn btn-outline modal-cancel">Cancelar</button>
                <button class="btn btn-primary" id="btnSaveMove">Mover</button>
            `,
        });

        // Load locations
        API.get('/ranches/1/locations').then(res => {
            if (res.success) {
                const $sel = $modal.find('#moveDestination');
                res.data.forEach(l => $sel.append(`<option value="${l.id}">${l.name}</option>`));
            }
        });

        $modal.find('.modal-cancel').on('click', () => Modal.close($modal));
        $modal.find('#btnSaveMove').on('click', async () => {
            const dest = $('#moveDestination').val();
            const reason = $('#moveReason').val();

            const res = await API.post('/movements', {
                animal_id: this.animalId, to_location_id: dest, reason, movement_date: new Date().toISOString().split('T')[0],
            });
            if (res.success) {
                Toast.success('Movimiento registrado');
                Modal.close($modal);
                this.loadProfile();
            } else {
                Toast.error(res.message || 'Error');
            }
        });
    },

    showDisposalModal() {
        const $modal = Modal.show({
            title: 'Registrar Baja / Muerte',
            body: `
                <div class="form-group">
                    <label>Tipo</label>
                    <select class="form-input" id="disposalType">
                        <option value="death">Muerte</option>
                        <option value="culling">Descarte</option>
                        <option value="euthanasia">Eutanasia</option>
                        <option value="loss">Pérdida</option>
                        <option value="other">Otro</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Motivo</label>
                    <textarea class="form-input" id="disposalReason" rows="2" required></textarea>
                </div>
                <div class="form-group">
                    <label>Fecha</label>
                    <input type="date" class="form-input" id="disposalDate" value="${new Date().toISOString().split('T')[0]}">
                </div>
            `,
            footer: `
                <button class="btn btn-outline modal-cancel">Cancelar</button>
                <button class="btn btn-danger" id="btnSaveDisposal">Confirmar Baja</button>
            `,
        });

        $modal.find('.modal-cancel').on('click', () => Modal.close($modal));
        $modal.find('#btnSaveDisposal').on('click', async () => {
            const confirmed = await Modal.confirm('Confirmar', '¿Estás seguro de registrar esta baja? Esta acción cambiará el estado del animal.');
            if (!confirmed) return;

            const res = await API.post('/disposals', {
                animal_id: this.animalId,
                disposal_type: $('#disposalType').val(),
                reason: $('#disposalReason').val(),
                disposal_date: $('#disposalDate').val(),
            });
            if (res.success) {
                Toast.success('Baja registrada');
                Modal.close($modal);
                window.location.reload();
            } else {
                Toast.error(res.message || 'Error');
            }
        });
    },

    showPhotoUploadModal() {
        const self = this;
        const $modal = Modal.show({
            title: 'Subir Fotos',
            body: `
                <div class="form-group">
                    <label class="form-label">Categoría de la foto</label>
                    <select class="form-input" id="photoContextSelect">
                        <option value="profile">📷 Perfil / General</option>
                        <option value="weight">⚖️ Peso / Engorda</option>
                        <option value="health">🏥 Salud</option>
                        <option value="treatment">💊 Tratamiento</option>
                        <option value="birth">🐣 Nacimiento</option>
                        <option value="task">✅ Tarea</option>
                        <option value="other">📎 Otro</option>
                    </select>
                </div>
                <div class="form-group">
                    <label class="form-label">Descripción (opcional)</label>
                    <input type="text" class="form-input" id="photoCaptionInput" placeholder="Ej: Peso semana 12, avance de engorda...">
                </div>
                <div class="photo-drop-zone" id="photoDropZone">
                    <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" style="color:var(--text-muted)">
                        <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
                        <circle cx="12" cy="13" r="4"/>
                    </svg>
                    <span>Click o arrastra fotos aquí</span>
                    <span style="font-size:.8rem;color:var(--text-muted)">Puedes seleccionar varias a la vez</span>
                    <input type="file" id="photoModalFileInput" accept="image/*" multiple style="display:none" capture="environment">
                </div>
                <div id="photoModalPreview" style="margin-top:12px"></div>
            `,
            footer: `
                <button class="btn btn-outline modal-cancel">Cancelar</button>
                <button class="btn btn-primary" id="btnUploadModalPhotos" disabled>Subir fotos</button>
            `,
        });

        let selectedFiles = [];
        const dropZone = document.getElementById('photoDropZone');
        const fileInput = document.getElementById('photoModalFileInput');
        const previewEl = document.getElementById('photoModalPreview');
        const uploadBtn = document.getElementById('btnUploadModalPhotos');

        // Drop zone click
        dropZone.addEventListener('click', (e) => {
            if (e.target === fileInput) return;
            fileInput.click();
        });
        dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.style.borderColor = 'var(--color-primary)'; });
        dropZone.addEventListener('dragleave', () => { dropZone.style.borderColor = ''; });
        dropZone.addEventListener('drop', (e) => {
            e.preventDefault();
            dropZone.style.borderColor = '';
            addFiles(Array.from(e.dataTransfer.files));
        });
        fileInput.addEventListener('change', () => {
            addFiles(Array.from(fileInput.files));
            fileInput.value = '';
        });

        function addFiles(files) {
            files.forEach(f => {
                if (f.type.startsWith('image/')) selectedFiles.push(f);
            });
            renderPreview();
        }

        function renderPreview() {
            if (!selectedFiles.length) {
                previewEl.innerHTML = '';
                uploadBtn.disabled = true;
                return;
            }
            uploadBtn.disabled = false;
            let html = '<div class="photo-modal-thumbs">';
            selectedFiles.forEach((f, i) => {
                const url = URL.createObjectURL(f);
                html += `<div class="photo-modal-thumb">
                    <img src="${url}" alt="">
                    <button type="button" class="photo-thumb-remove" data-rm-idx="${i}">&times;</button>
                </div>`;
            });
            html += `</div><div style="font-size:.85rem;color:var(--text-secondary);margin-top:4px">${selectedFiles.length} foto${selectedFiles.length > 1 ? 's' : ''}</div>`;
            previewEl.innerHTML = html;

            previewEl.querySelectorAll('[data-rm-idx]').forEach(btn => {
                btn.addEventListener('click', function() {
                    selectedFiles.splice(parseInt(this.dataset.rmIdx), 1);
                    renderPreview();
                });
            });
        }

        $modal.find('.modal-cancel').on('click', () => Modal.close($modal));
        $modal.find('#btnUploadModalPhotos').on('click', async () => {
            if (!selectedFiles.length) return;
            const context = document.getElementById('photoContextSelect').value;
            const caption = document.getElementById('photoCaptionInput').value;

            uploadBtn.disabled = true;
            uploadBtn.innerHTML = '<span class="loader-inline"></span> Subiendo...';

            let ok = 0;
            for (const file of selectedFiles) {
                const res = await API.upload(`/animals/${self.animalId}/photos`, file, 'photo', {
                    context: context,
                    caption: caption || null,
                });
                if (res.success !== false) ok++;
            }

            if (ok > 0) {
                Toast.success(`${ok} foto${ok > 1 ? 's' : ''} subida${ok > 1 ? 's' : ''}`);
                Modal.close($modal);
                await self.loadProfile();
                self.loadPhotos();
            } else {
                Toast.error('Error subiendo fotos');
                uploadBtn.disabled = false;
                uploadBtn.innerHTML = 'Subir fotos';
            }
        });
    },

    async uploadPhotosWithContext(files, context) {
        if (!files || !files.length) return;

        for (const file of files) {
            const res = await API.upload(`/animals/${this.animalId}/photos`, file, 'photo', { context });
            if (res.success !== false) {
                Toast.success('Foto subida');
            } else {
                Toast.error('Error subiendo foto');
            }
        }
        await this.loadProfile();
        this.loadPhotos();
    },

    // ─── DOCUMENTS ──────────────────────────────────────────

    async loadDocuments() {
        try {
            const res = await API.get(`/animals/${this.animalId}/documents`);
            const docs = res.data || [];
            const container = document.getElementById('documentsList');
            if (!container) return;

            if (!docs.length) {
                container.innerHTML = '<div class="empty-state"><p>Sin documentos adjuntos</p><p class="text-muted">Sube archivos PDF, Word, Excel o imágenes</p></div>';
                return;
            }

            const html = docs.map(d => {
                const icon = this.getDocIcon(d.mime_type);
                const size = this.formatFileSize(d.file_size);
                const date = d.created_at ? App.formatDate(d.created_at) : '';
                const typeBadge = d.document_type ? `<span class="chip chip-sm">${d.document_type}</span>` : '';

                return `<div class="doc-item">
                    <div class="doc-icon">${icon}</div>
                    <div class="doc-info">
                        <div class="doc-title"><strong>${d.title || d.file_name}</strong> ${typeBadge}</div>
                        <div class="doc-meta">${size} · ${date}${d.uploaded_by_name ? ' · ' + d.uploaded_by_name : ''}</div>
                        ${d.description ? `<div class="doc-desc">${d.description}</div>` : ''}
                    </div>
                    <div class="doc-actions">
                        <a href="/api/documents/${d.id}/download" class="btn btn-sm btn-ghost" title="Descargar" target="_blank">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
                        </a>
                        <button class="btn btn-sm btn-ghost text-danger" onclick="AnimalProfile.deleteDocument(${d.id})" title="Eliminar">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
                        </button>
                    </div>
                </div>`;
            }).join('');

            container.innerHTML = html;
        } catch(e) {
            const container = document.getElementById('documentsList');
            if (container) container.innerHTML = '<div class="empty-state"><p>Error al cargar documentos</p></div>';
        }
    },

    showDocumentUpload() {
        const $modal = Modal.show({
            title: 'Subir Documento',
            body: `
                <div class="form-group">
                    <label class="form-label">Archivo *</label>
                    <div class="doc-drop-zone" id="docDropZone">
                        <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" style="color:var(--text-muted)">
                            <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><line x1="9" y1="15" x2="15" y2="15"/>
                        </svg>
                        <span>Click o arrastra un archivo aquí</span>
                        <input type="file" id="docFileModal" accept=".pdf,.doc,.docx,.xls,.xlsx,.csv,.txt,.jpg,.jpeg,.png,.webp" style="display:none">
                    </div>
                    <div id="docFileInfo" style="display:none;margin-top:0.5rem;font-size:0.85rem;color:var(--text-secondary)"></div>
                </div>
                <div class="form-group">
                    <label class="form-label">Título</label>
                    <input type="text" class="form-input" id="docTitle" placeholder="Nombre del documento">
                </div>
                <div class="form-group">
                    <label class="form-label">Tipo</label>
                    <select class="form-input" id="docType">
                        <option value="other">General</option>
                        <option value="certificate">Certificado</option>
                        <option value="health_record">Registro de salud</option>
                        <option value="pedigree">Pedigrí / Genealogía</option>
                        <option value="purchase">Compra</option>
                        <option value="vaccination">Certificado vacunación</option>
                        <option value="lab_result">Resultado laboratorio</option>
                        <option value="invoice">Factura</option>
                    </select>
                </div>
                <div class="form-group">
                    <label class="form-label">Descripción (opcional)</label>
                    <textarea class="form-input" id="docDescription" rows="2" placeholder="Notas sobre el documento"></textarea>
                </div>
            `,
            footer: `
                <button class="btn btn-outline modal-cancel">Cancelar</button>
                <button class="btn btn-primary" id="btnSaveDoc">Subir documento</button>
            `,
        });

        let selectedFile = null;
        const dropZone = document.getElementById('docDropZone');
        const fileInput = document.getElementById('docFileModal');

        dropZone.addEventListener('click', () => fileInput.click());
        dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.style.borderColor = 'var(--color-primary)'; });
        dropZone.addEventListener('dragleave', () => { dropZone.style.borderColor = ''; });
        dropZone.addEventListener('drop', (e) => {
            e.preventDefault();
            dropZone.style.borderColor = '';
            if (e.dataTransfer.files[0]) handleFile(e.dataTransfer.files[0]);
        });

        fileInput.addEventListener('change', (e) => {
            if (e.target.files[0]) handleFile(e.target.files[0]);
        });

        function handleFile(file) {
            selectedFile = file;
            document.getElementById('docFileInfo').style.display = '';
            document.getElementById('docFileInfo').textContent = `📄 ${file.name} (${AnimalProfile.formatFileSize(file.size)})`;
            dropZone.innerHTML = `<span style="color:var(--color-primary);font-weight:600">✓ Archivo seleccionado</span>`;
            if (!document.getElementById('docTitle').value) {
                document.getElementById('docTitle').value = file.name.replace(/\.[^.]+$/, '');
            }
        }

        $modal.find('.modal-cancel').on('click', () => Modal.close($modal));
        $modal.find('#btnSaveDoc').on('click', async () => {
            if (!selectedFile) { Toast.warning('Selecciona un archivo'); return; }

            const fd = new FormData();
            fd.append('document', selectedFile);
            fd.append('title', document.getElementById('docTitle').value || selectedFile.name);
            fd.append('document_type', document.getElementById('docType').value);
            fd.append('description', document.getElementById('docDescription').value || '');

            try {
                const res = await API.request('POST', `/animals/${this.animalId}/documents`, fd);
                if (res.success !== false) {
                    Toast.success('Documento subido exitosamente');
                    Modal.close($modal);
                    this.loadDocuments();
                } else {
                    Toast.danger(res.message || 'Error al subir documento');
                }
            } catch(e) {
                Toast.danger('Error al subir documento');
            }
        });
    },

    async deleteDocument(docId) {
        if (!confirm('¿Eliminar este documento?')) return;
        try {
            await API.delete(`/documents/${docId}`);
            Toast.success('Documento eliminado');
            this.loadDocuments();
        } catch(e) { Toast.danger('Error al eliminar documento'); }
    },

    getDocIcon(mimeType) {
        if (!mimeType) return '📄';
        if (mimeType.includes('pdf')) return '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#DC2626" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>';
        if (mimeType.includes('word') || mimeType.includes('document')) return '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#2563EB" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>';
        if (mimeType.includes('sheet') || mimeType.includes('excel') || mimeType.includes('csv')) return '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="10" y1="12" x2="14" y2="18"/><line x1="14" y1="12" x2="10" y2="18"/></svg>';
        if (mimeType.includes('image')) return '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#D97706" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>';
        return '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>';
    },

    formatFileSize(bytes) {
        if (!bytes) return '—';
        if (bytes < 1024) return bytes + ' B';
        if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
        return (bytes / 1048576).toFixed(1) + ' MB';
    },

    // ─── HELPERS ────────────────────────────────────────────

    calcAge(birthDate) {
        const birth = new Date(birthDate + 'T00:00:00');
        const now = new Date();
        const months = (now.getFullYear() - birth.getFullYear()) * 12 + (now.getMonth() - birth.getMonth());
        if (months < 1) return Math.floor((now - birth) / 86400000) + ' días';
        if (months < 12) return months + ' meses';
        const years = Math.floor(months / 12);
        const rem = months % 12;
        return rem > 0 ? `${years} años ${rem}m` : `${years} años`;
    },

    getStatusChip(status) {
        const labels = { active: 'Activo', sold: 'Vendido', disposed: 'Dado de baja', dead: 'Muerto', inactive: 'Inactivo' };
        const styles = { active: 'chip-success', sold: 'chip-info', disposed: 'chip-warning', dead: 'chip-danger', inactive: 'chip-outline' };
        const icons = { active: '●', sold: '💰', disposed: '▼', dead: '✕', inactive: '○' };
        const label = labels[status] || status || '—';
        return `<span class="chip ${styles[status] || ''}">${icons[status] || ''} ${label}</span>`;
    },

    getHealthChip(status) {
        const labels = { healthy: 'Sano', sick: 'Enfermo', quarantine: 'Cuarentena', treatment: 'En tratamiento', recovering: 'Recuperación' };
        const styles = { healthy: 'chip-success', sick: 'chip-danger', quarantine: 'chip-warning', treatment: 'chip-accent', recovering: 'chip-info' };
        const icons = { healthy: '♥', sick: '⚠', quarantine: '⛔', treatment: '💊', recovering: '↻' };
        const label = labels[status] || status || 'Sano';
        const style = styles[status] || 'chip-success';
        const icon = icons[status] || '♥';
        return `<span class="chip ${style}">${icon} ${label}</span>`;
    },

    getReproductiveLabel(status) {
        const labels = {
            not_applicable: null, open: 'Abierta', pregnant: 'Gestante', lactating: 'Lactando',
            dry: 'Seca', breeding: 'En monta', inseminated: 'Inseminada', calving: 'En parto',
            resting: 'Descanso', stud: 'Semental', castrated: 'Castrado'
        };
        return labels[status] !== undefined ? labels[status] : status;
    },
};
