const express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const multer = require('multer');

const app = express();
app.use(cors({ origin: ['https://med.a-life.co', 'https://api.med.a-life.co'], credentials: false }));
app.use(express.json({ limit: '20mb' }));

const DATA = path.join(__dirname, 'data.json');
const UP = path.join(__dirname, 'uploads');
if (!fs.existsSync(UP)) fs.mkdirSync(UP, { recursive: true });
app.use('/uploads', express.static(UP));

const FRONTEND_DIST = path.join(__dirname, '..', 'frontend', 'dist');


const now = () => new Date().toISOString();
const id = p => p + Date.now() + Math.floor(Math.random() * 9999);
const clean = v => String(v || '').trim();
const productList = x => clean(x).split(/[,;\n]/).map(v => clean(v)).filter(Boolean);

const seed = {
  users: [
    { id: 'u1', username: 'Diellza', name: 'Diellza', password: '1234', role: 'admin', active: true },
    { id: 'u2', username: 'Fikret', name: 'Fikret', password: '1234', role: 'representative', active: true },
    { id: 'u3', username: 'Lirika', name: 'Lirika', password: '1234', role: 'representative', active: true },
    { id: 'u4', username: 'Harisa', name: 'Harisa', password: '1234', role: 'representative', active: true },
    { id: 'u5', username: 'Xheneta', name: 'Xheneta', password: '1234', role: 'representative', active: true }
  ],
  contacts: [],
  visits: [],
  salesFiles: [],
  notifications: [],
  suggestions: {
    names: [],
    products: ['Buonerbe', 'Larimucil'],
    specializations: ['Pediater', 'Urolog', 'Gjinekolog', 'Dermatolog', 'Kardiolog', 'Mjek familjar', 'Farmacist'],
    cities: ['Prishtine', 'Prizren', 'Peje', 'Gjilan', 'Ferizaj', 'Gjakove', 'Mitrovice'],
    institutions: ['QKUK', 'QKMF', 'Spitali Rajonal', 'Farmaci private', 'Poliklinike private']
  }
};

function load() {
  if (!fs.existsSync(DATA)) fs.writeFileSync(DATA, JSON.stringify(seed, null, 2));
  const d = JSON.parse(fs.readFileSync(DATA, 'utf8'));
  d.users = d.users && d.users.length ? d.users : seed.users;
  d.contacts = d.contacts || [];
  d.visits = d.visits || d.tasks || [];
  d.salesFiles = d.salesFiles || [];
  d.notifications = d.notifications || [];
  d.suggestions = { ...seed.suggestions, ...(d.suggestions || {}) };
  d.suggestions.products = d.suggestions.products || seed.suggestions.products;
  return d;
}
let db = load();
const save = () => fs.writeFileSync(DATA, JSON.stringify(db, null, 2));

function safe(u, show = false) {
  if (!u) return null;
  const x = { id: u.id, username: u.username, name: u.name, role: u.role, active: u.active !== false, createdAt: u.createdAt };
  if (show) x.password = u.password;
  return x;
}
function addSug(group, value) {
  value = clean(value);
  if (!value) return;
  db.suggestions[group] = db.suggestions[group] || [];
  if (!db.suggestions[group].some(x => x.toLowerCase() === value.toLowerCase())) db.suggestions[group].push(value);
}
function ensureContact(r = {}) {
  const name = clean(r.name || r.targetName);
  if (!name) return null;
  const type = clean(r.type || r.targetType || 'doctor');
  const specialization = clean(r.specialization || (type === 'pharmacy' ? 'Farmaci' : ''));
  const city = clean(r.city);
  const institution = clean(r.institution || r.pharmacyName);
  let c = db.contacts.find(x => clean(x.name).toLowerCase() === name.toLowerCase() && clean(x.city).toLowerCase() === city.toLowerCase());
  const base = { type, name, specialization, city, institution, phone: clean(r.phone), updatedAt: now() };
  if (c) Object.assign(c, { ...base, phone: base.phone || c.phone });
  else {
    c = { id: id('c'), ...base, createdAt: now() };
    db.contacts.push(c);
  }
  addSug('names', name); addSug('specializations', specialization); addSug('cities', city); addSug('institutions', institution);
  return c;
}
function enrich(v) {
  return { ...v, representative: safe(db.users.find(u => u.id === v.representativeId)), contact: db.contacts.find(c => c.id === v.contactId) || null };
}
function hist(v, by, text) {
  v.history = v.history || [];
  v.history.push({ at: now(), by: by || 'System', text });
  v.updatedAt = now();
}
function notify(role, text, visitId, extra = {}) {
  db.notifications = db.notifications || [];
  db.notifications.unshift({ id: id('n'), role, text, visitId, read: false, createdAt: now(), ...extra });
}
function sameProducts(a, b) {
  const aa = productList(a).map(x => x.toLowerCase()).sort().join('|');
  const bb = productList(b).map(x => x.toLowerCase()).sort().join('|');
  return aa === bb;
}
function filterVisits(query = {}) {
  let rows = [...db.visits];
  const { representativeId, rep, status, source, from, to, q, product, city, specialization } = query;
  const repId = representativeId || rep;
  if (repId) rows = rows.filter(v => v.representativeId === repId);
  if (status && status !== 'all') rows = rows.filter(v => v.status === status);
  if (source && source !== 'all') rows = rows.filter(v => v.source === source);
  if (from) rows = rows.filter(v => String(v.completedAt || v.startedAt || v.date || v.createdAt) >= from);
  if (to) rows = rows.filter(v => String(v.completedAt || v.startedAt || v.date || v.createdAt) <= to + 'T23:59:59');
  if (city) rows = rows.filter(v => clean(v.city).toLowerCase() === clean(city).toLowerCase());
  if (specialization) rows = rows.filter(v => clean(v.specialization).toLowerCase() === clean(specialization).toLowerCase());
  if (product) rows = rows.filter(v => productList((v.report && v.report.products) || v.assignedProducts).some(x => x.toLowerCase().includes(clean(product).toLowerCase())));
  if (q) rows = rows.filter(v => JSON.stringify(v).toLowerCase().includes(String(q).toLowerCase()));
  return rows;
}
function durationMin(v) {
  if (!v.startedAt || !v.completedAt) return null;
  return Math.max(0, Math.round((new Date(v.completedAt) - new Date(v.startedAt)) / 60000));
}
function durationSec(v) {
  if (!v.startedAt || !v.completedAt) return null;
  return Math.max(0, Math.round((new Date(v.completedAt) - new Date(v.startedAt)) / 1000));
}
function displayTarget(v) { const n = clean(v.name); if (n && !/^target$/i.test(n)) return n; return clean(v.institution) || clean(v.title) || '-'; }
function displayType(v) { return v.targetType === 'pharmacy' ? 'Farmaci' : 'Doktor'; }
function stats(query = {}) {
  let rows = db.visits.filter(v => v.status === 'completed');
  if (query.rep) rows = rows.filter(v => v.representativeId === query.rep);
  if (query.from) rows = rows.filter(v => (v.completedAt || v.date) >= query.from);
  if (query.to) rows = rows.filter(v => (v.completedAt || v.date) <= query.to + 'T23:59:59');
  const count = fn => rows.filter(fn).length;
  const group = fn => rows.reduce((a, v) => { const k = fn(v) || 'Pa info'; a[k] = (a[k] || 0) + 1; return a; }, {});
  const reps = db.users.filter(u => u.role === 'representative' && u.active !== false).map(u => {
    const r = rows.filter(v => v.representativeId === u.id);
    return { id: u.id, name: u.name, total: r.length, doctor: r.filter(v => v.targetType !== 'pharmacy').length, pharmacy: r.filter(v => v.targetType === 'pharmacy').length };
  });
  const productMap = {};
  const productByRep = {};
  rows.forEach(v => productList(v.report && v.report.products).forEach(prod => {
    productMap[prod] = productMap[prod] || {};
    const key = displayTarget(v);
    productMap[prod][key] = productMap[prod][key] || { name: key, type: v.targetType || 'doctor', specialization: v.specialization, city: v.city, count: 0 };
    productMap[prod][key].count += 1;
    const rep = (db.users.find(u => u.id === v.representativeId) || {}).name || 'Pa rep';
    productByRep[prod] = productByRep[prod] || {};
    productByRep[prod][rep] = (productByRep[prod][rep] || 0) + 1;
  }));
  const productDoctorMatrix = Object.entries(productMap).map(([product, contacts]) => ({
    product,
    contacts: Object.values(contacts).sort((a, b) => b.count - a.count),
    doctors: Object.values(contacts).map(x => x.name),
    byRep: productByRep[product] || {}
  })).sort((a, b) => b.contacts.length - a.contacts.length);
  return {
    total: rows.length,
    doctor: count(v => v.targetType !== 'pharmacy'),
    pharmacy: count(v => v.targetType === 'pharmacy'),
    assigned: count(v => v.source === 'assigned'),
    spontaneous: count(v => v.source === 'spontaneous'),
    bySpecialization: group(v => v.specialization),
    byCity: group(v => v.city),
    byRep: reps,
    productDoctorMatrix,
    pending: db.visits.filter(v => v.status === 'pending').length,
    inProgress: db.visits.filter(v => v.status === 'in_progress').length
  };
}
const upload = multer({ storage: multer.diskStorage({ destination: UP, filename: (req, file, cb) => cb(null, Date.now() + '-' + file.originalname.replace(/[^a-zA-Z0-9._-]/g, '_')) }) });

app.post('/api/login', (req, res) => {
  const u = db.users.find(x => x.active !== false && clean(x.username).toLowerCase() === clean(req.body.username).toLowerCase() && x.password === req.body.password);
  if (!u) return res.status(401).json({ message: 'Login gabim' });
  res.json({ user: safe(u) });
});
app.get('/api/meta', (req, res) => res.json({ users: db.users.map(u => safe(u)), contacts: db.contacts, suggestions: db.suggestions }));
app.get('/api/admin/users', (req, res) => res.json(db.users.map(u => safe(u, true))));
app.post('/api/admin/users', (req, res) => {
  const b = req.body, username = clean(b.username || b.name);
  if (!username || !clean(b.password)) return res.status(400).json({ message: 'Emri/password mungon' });
  if (db.users.some(u => clean(u.username).toLowerCase() === username.toLowerCase())) return res.status(409).json({ message: 'Username ekziston' });
  const u = { id: id('u'), username, name: clean(b.name || username), password: clean(b.password), role: b.role || 'representative', active: true, createdAt: now() };
  db.users.push(u); save(); res.status(201).json(safe(u, true));
});
app.put('/api/admin/users/:id', (req, res) => {
  const u = db.users.find(x => x.id === req.params.id); if (!u) return res.sendStatus(404);
  ['name', 'username', 'password', 'role'].forEach(k => { if (req.body[k] !== undefined) u[k] = clean(req.body[k]); });
  if (req.body.active !== undefined) u.active = !!req.body.active;
  save(); res.json(safe(u, true));
});
app.delete('/api/admin/users/:id', (req, res) => { const u = db.users.find(x => x.id === req.params.id); if (!u) return res.sendStatus(404); u.active = false; save(); res.json({ ok: true }); });

app.get('/api/visits', (req, res) => {
  let out = [...db.visits];
  const { representativeId, status, source, from, to, q, limit = '100', offset = '0', queue } = req.query;
  if (representativeId) out = out.filter(v => v.representativeId === representativeId);
  if (queue === 'rep') {
    const day = to || now().slice(0, 10);
    out = out.filter(v => {
      const visitDay = String(v.completedAt || v.startedAt || v.date || v.createdAt).slice(0, 10);
      const isOpenOrOverdue = v.status !== 'completed' && String(v.date || visitDay) <= day;
      const isTodayActivity = visitDay === day;
      return isOpenOrOverdue || isTodayActivity;
    });
  }
  if (status && status !== 'all') out = out.filter(v => v.status === status);
  if (source && source !== 'all') out = out.filter(v => v.source === source);
  if (queue !== 'rep' && from) out = out.filter(v => (v.date || v.createdAt) >= from);
  if (queue !== 'rep' && to) out = out.filter(v => (v.date || v.createdAt) <= to + 'T23:59:59');
  if (q) out = out.filter(v => JSON.stringify(v).toLowerCase().includes(String(q).toLowerCase()));
  out = out.map(enrich).map(v => ({ ...v, durationMinutes: durationMin(v), durationSeconds: durationSec(v) })).sort((a, b) => String(b.completedAt || b.startedAt || b.createdAt).localeCompare(String(a.completedAt || a.startedAt || a.createdAt)));
  res.json({ total: out.length, items: out.slice(+offset, +offset + +limit) });
});
app.post('/api/visits/assigned', (req, res) => {
  const b = req.body, c = ensureContact(b.contact || b);
  const v = { id: id('v'), source: 'assigned', status: 'pending', title: clean(b.title) || 'Task vizite', representativeId: b.representativeId, contactId: c && c.id, targetType: (c && c.type) || b.targetType || 'doctor', name: (c && c.name) || '', specialization: (c && c.specialization) || '', city: (c && c.city) || '', institution: (c && c.institution) || '', date: clean(b.date), time: clean(b.time) || '09:00', priority: b.priority || 'Medium', instructions: clean(b.instructions), assignedProducts: clean(b.assignedProducts), createdBy: b.byName || 'Diellza', createdAt: now(), sentAt: now(), startedAt: null, completedAt: null, startLocation: null, endLocation: null, location: null, report: null, locked: true, correctionRequested: null, history: [] };
  hist(v, v.createdBy, 'Admin krijoi dhe dergoi task.'); db.visits.push(v); save(); res.status(201).json(enrich(v));
});
app.post('/api/visits/open', (req, res) => {
  const b = req.body, c = ensureContact(b);
  const v = { id: id('v'), source: b.source || 'spontaneous', status: 'in_progress', title: clean(b.title) || 'Vizite ne terren', representativeId: b.representativeId, contactId: c && c.id, targetType: b.targetType || b.type || (c && c.type) || 'doctor', name: b.name || (c && c.name) || '', specialization: b.specialization || (c && c.specialization) || '', city: b.city || (c && c.city) || '', institution: b.institution || (c && c.institution) || '', date: b.date || now().slice(0, 10), time: b.time || new Date().toTimeString().slice(0, 5), createdBy: b.byName, createdAt: now(), startedAt: now(), completedAt: null, startLocation: b.location || null, endLocation: null, location: b.location || null, report: null, locked: true, correctionRequested: null, history: [] };
  hist(v, b.byName, 'Representative hapi viziten. Te dhenat kryesore u bllokuan pas startimit.'); db.visits.push(v); save(); res.status(201).json(enrich(v));
});
app.put('/api/visits/:id', (req, res) => {
  const v = db.visits.find(x => x.id === req.params.id); if (!v) return res.sendStatus(404);
  const p = req.body;
  if (p.status === 'in_progress' && v.status === 'pending') {
    v.status = 'in_progress'; v.startedAt = now(); v.startLocation = p.location || null; v.location = p.location || v.location; v.locked = true;
    hist(v, p.byName, 'Representative nisi viziten. Te dhenat kryesore u bllokuan.');
  }
  if (p.report) {
    // After start, target/contact fields stay locked. Only report fields are accepted from representative.
    v.status = 'completed'; v.completedAt = now(); v.endLocation = p.location || null; v.location = p.location || v.location;
    const reportProducts = clean(p.report.products) || clean(v.assignedProducts);
    const targetProducts = clean(v.assignedProducts);
    v.report = { result: clean(p.report.result), targetProducts, products: reportProducts, notes: clean(p.report.notes), submittedAt: now() };
    productList(reportProducts).forEach(x => addSug('products', x));
    if (v.source === 'assigned' && targetProducts && !sameProducts(targetProducts, reportProducts)) {
      const repName = (db.users.find(u => u.id === v.representativeId) || {}).name || p.byName || 'Representative';
      notify('admin', `${repName} ndryshoi produktin ne task: ${targetProducts} -> ${reportProducts}`, v.id, { type: 'product_changed', representativeId: v.representativeId, oldProducts: targetProducts, newProducts: reportProducts });
      hist(v, p.byName, `Produkti u ndryshua nga ${targetProducts} ne ${reportProducts}; admini u njoftua.`);
    }
    hist(v, p.byName, 'Representative perfundoi viziten dhe dergoi raportin.');
  }
  if (p.correctionNote) {
    v.correctionRequested = { note: clean(p.correctionNote), by: p.byName, at: now(), status: 'open' };
    hist(v, p.byName, 'Representative raportoi gabim per korrigjim nga admin.');
  }
  save(); res.json({ ...enrich(v), durationMinutes: durationMin(v), durationSeconds: durationSec(v) });
});
app.put('/api/admin/visits/:id', (req, res) => {
  const v = db.visits.find(x => x.id === req.params.id); if (!v) return res.sendStatus(404);
  const b = req.body;
  const allowed = ['name', 'specialization', 'city', 'institution', 'targetType', 'date', 'time', 'instructions', 'title', 'assignedProducts'];
  allowed.forEach(k => { if (b[k] !== undefined) v[k] = clean(b[k]); });
  if (b.name || b.city || b.specialization || b.institution || b.targetType) {
    const c = ensureContact({ name: v.name, city: v.city, specialization: v.specialization, institution: v.institution, targetType: v.targetType });
    if (c) v.contactId = c.id;
  }
  if (v.correctionRequested) v.correctionRequested.status = 'resolved';
  hist(v, b.byName || 'Admin', 'Admin korrigjoi te dhenat e vizites/task-ut.');
  save(); res.json(enrich(v));
});
function deleteVisitById(req, res) {
  const before = db.visits.length;
  const item = db.visits.find(v => v.id === req.params.id);
  db.visits = db.visits.filter(v => v.id !== req.params.id);
  if (db.visits.length === before) return res.status(404).json({ error: 'Not found' });
  save();
  res.json({ ok: true, deletedId: req.params.id, source: item?.source || null });
}
app.delete('/api/visits/:id', deleteVisitById);
app.delete('/api/tasks/:id', deleteVisitById);
app.get('/api/stats', (req, res) => res.json(stats(req.query)));


app.get('/api/notifications', (req, res) => {
  const role = req.query.role || 'admin';
  res.json((db.notifications || []).filter(n => !n.role || n.role === role).slice(0, 50));
});
app.put('/api/notifications/:id/read', (req, res) => {
  const n = (db.notifications || []).find(x => x.id === req.params.id);
  if (!n) return res.sendStatus(404);
  n.read = true; save(); res.json(n);
});
function reportRows(query) {
  return filterVisits(query).map(enrich).map(v => ({ ...v, durationMinutes: durationMin(v), durationSeconds: durationSec(v) }))
    .sort((a, b) => String(b.completedAt || b.startedAt || b.createdAt).localeCompare(String(a.completedAt || a.startedAt || a.createdAt)));
}
function htmlEscape(x) { return String(x || '').replace(/[&<>]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;'}[c])); }
function csvCell(x) { return '"' + String(x ?? '').replace(/"/g, '""') + '"'; }
function makePdf(lines) {
  const cleanPdf = x => String(x || '').replace(/[\r\n]+/g, ' ').replace(/[()\\]/g, m => '\\' + m).slice(0, 110);
  let y = 800;
  const stream = [];
  stream.push('0.07 0.16 0.32 rg 0 760 612 90 re f');
  stream.push('1 1 1 rg BT /F1 22 Tf 40 815 Td (A-Life Field Report) Tj ET');
  stream.push('0.90 0.95 1 rg BT /F1 10 Tf 40 790 Td (Medical Representatives / Admin report) Tj ET');
  y = 735;
  lines.forEach((line, i) => {
    if (i < 7) { stream.push('0.95 0.97 1 rg 40 ' + (y-9) + ' 532 24 re f'); }
    stream.push('0.08 0.14 0.23 rg BT /F1 ' + (i < 7 ? 12 : 9) + ' Tf 50 ' + y + ' Td (' + cleanPdf(line) + ') Tj ET');
    y -= i < 7 ? 30 : 15;
    if (y < 45) return;
  });
  const content = stream.join('\n');
  const objects = [];
  objects.push('1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj');
  objects.push('2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj');
  objects.push('3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 842] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >> endobj');
  objects.push('4 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj');
  objects.push('5 0 obj << /Length ' + Buffer.byteLength(content, 'latin1') + ' >> stream\n' + content + '\nendstream endobj');
  let pdf = '%PDF-1.4\n';
  const offsets = [0];
  for (const obj of objects) { offsets.push(Buffer.byteLength(pdf, 'latin1')); pdf += obj + '\n'; }
  const xref = Buffer.byteLength(pdf, 'latin1');
  pdf += 'xref\n0 ' + (objects.length + 1) + '\n0000000000 65535 f \n';
  for (let i = 1; i < offsets.length; i++) pdf += String(offsets[i]).padStart(10, '0') + ' 00000 n \n';
  pdf += 'trailer << /Size ' + (objects.length + 1) + ' /Root 1 0 R >>\nstartxref\n' + xref + '\n%%EOF';
  return Buffer.from(pdf, 'latin1');
}
app.get('/api/export/pdf', (req, res) => {
  const rows = reportRows(req.query);
  const st = stats(req.query);
  const titleRange = `${req.query.from || 'fillimi'} - ${req.query.to || 'sot'}`;
  const lines = [
    `Periudha: ${titleRange}`,
    `Total vizita: ${st.total || 0}`,
    `Doktore: ${st.doctor || 0}    Farmaci: ${st.pharmacy || 0}`,
    `Task nga admin: ${st.assigned || 0}    Vizita spontane: ${st.spontaneous || 0}`,
    `Produkte kryesore: ${(st.productDoctorMatrix || []).slice(0, 5).map(x => `${x.product} (${x.contacts.length})`).join(', ') || '-'}`,
    `Qytete: ${Object.entries(st.byCity || {}).map(([k,v]) => `${k}:${v}`).slice(0,6).join(', ') || '-'}`,
    `Specializime: ${Object.entries(st.bySpecialization || {}).map(([k,v]) => `${k}:${v}`).slice(0,6).join(', ') || '-'}`,
    '', 'Vizitat e fundit:',
    ...rows.slice(0, 28).map(v => `${String(v.completedAt || v.startedAt || v.createdAt).slice(0,16).replace('T',' ')} | ${(v.representative || {}).name || ''} | ${displayTarget(v)} | ${displayType(v)} | ${v.city || ''} | ${(v.report || {}).products || v.assignedProducts || ''} | ${v.status}`)
  ];
  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', `attachment; filename="alife-report-${Date.now()}.pdf"`);
  res.send(makePdf(lines));
});
app.get('/api/export/excel', (req, res) => {
  const rows = reportRows(req.query);
  const st = stats(req.query);
  const summary = [
    ['Metric','Value'], ['Total visits', st.total], ['Doctors', st.doctor], ['Pharmacies', st.pharmacy], ['Assigned tasks', st.assigned], ['Spontaneous visits', st.spontaneous]
  ];
  const visitRows = [['Date','Representative','Source','Status','Doctor/Pharmacy','Type','Specialization','City','Target products','Reported products','Result','Notes','Duration min'],
    ...rows.map(v => [fmtServer(v.completedAt || v.startedAt || v.createdAt), (v.representative || {}).name || '', v.source, v.status, displayTarget(v), displayType(v), v.specialization, v.city, v.assignedProducts || '', (v.report || {}).products || '', (v.report || {}).result || '', (v.report || {}).notes || '', v.durationMinutes ?? ''])];
  const productRows = [['Product','Contacts','Top contacts'], ...(st.productDoctorMatrix || []).map(x => [x.product, x.contacts.length, x.contacts.slice(0, 12).map(c => `${c.name} (${c.count})`).join(', ')])];
  const table = rows => '<table border="1">' + rows.map(r => '<tr>' + r.map(c => '<td>' + htmlEscape(c) + '</td>').join('') + '</tr>').join('') + '</table>';
  const html = `<html><head><meta charset="utf-8"></head><body><h1>A-Life Field Report</h1><h2>Summary</h2>${table(summary)}<h2>Visits</h2>${table(visitRows)}<h2>Products</h2>${table(productRows)}</body></html>`;
  res.setHeader('Content-Type', 'application/vnd.ms-excel; charset=utf-8');
  res.setHeader('Content-Disposition', `attachment; filename="alife-report-${Date.now()}.xls"`);
  res.send(html);
});
function fmtServer(x) { return x ? new Date(x).toISOString().slice(0,16).replace('T',' ') : ''; }

app.post('/api/sales/upload', upload.single('file'), (req, res) => { const f = { id: id('f'), representativeId: req.body.representativeId, title: req.body.title || req.file.originalname, originalName: req.file.originalname, filename: req.file.filename, uploadedAt: now() }; db.salesFiles.push(f); save(); res.status(201).json(f); });
app.get('/api/sales', (req, res) => { let out = [...db.salesFiles]; if (req.query.representativeId) out = out.filter(f => f.representativeId === req.query.representativeId); res.json(out.map(f => ({ ...f, representative: safe(db.users.find(u => u.id === f.representativeId)), downloadUrl: `${req.protocol}://${req.get('host')}/uploads/${f.filename}` }))); });

if (fs.existsSync(FRONTEND_DIST)) {
  app.use(express.static(FRONTEND_DIST));
  app.use((req, res, next) => {
    if (req.path.startsWith('/api') || req.path.startsWith('/uploads')) return next();
    res.sendFile(path.join(FRONTEND_DIST, 'index.html'));
  });
}

const PORT = process.env.PORT || 5000;
app.listen(PORT, '0.0.0.0', () => console.log(`A-Life online app running on port ${PORT}`));
