#!/usr/bin/env node
// FreeScout time tracking CLI — query timelogs and generate invoice Excel
const mysql = require('mysql2/promise');
const ExcelJS = require('exceljs');
const fs = require('fs');
const path = require('path');

const credFile = process.env.CRED_FILE || path.join(__dirname, '..', '.credentials', 'services.env');
const env = {};
fs.readFileSync(credFile, 'utf8').split('\n').forEach(l => { const m = l.match(/^(\w+)=(.+)$/); if (m) env[m[1]] = m[2]; });

async function getConn() {
  return mysql.createConnection({
    host: env.CLOONAR_DB_HOST,
    port: parseInt(env.CLOONAR_DB_PORT || '3306'),
    user: env.CLOONAR_DB_USER,
    password: env.CLOONAR_DB_PASS,
    database: env.FREESCOUT_DB_NAME,
  });
}

// Load custom field dropdown options (id -> {optionId: label})
async function loadCustomFieldOptions(conn) {
  const [fields] = await conn.query('SELECT id, name, options FROM custom_fields');
  const map = {};
  fields.forEach(f => {
    map[f.name.toLowerCase()] = { id: f.id, options: f.options ? JSON.parse(f.options) : {} };
  });
  return map;
}

function formatHours(seconds) {
  const h = seconds / 3600;
  return Math.round(h * 100) / 100;
}

// Get custom field values for conversations, resolved to labels
async function getConversationCustomFields(conn, conversationIds, cfMap) {
  if (!conversationIds.length) return {};
  const [rows] = await conn.query(
    'SELECT conversation_id, custom_field_id, value FROM conversation_custom_field WHERE conversation_id IN (?)',
    [conversationIds]
  );
  // Build: { convId: { fieldName: resolvedValue } }
  const result = {};
  const idToField = {};
  Object.entries(cfMap).forEach(([name, f]) => { idToField[f.id] = { name, options: f.options }; });

  rows.forEach(r => {
    if (!result[r.conversation_id]) result[r.conversation_id] = {};
    const field = idToField[r.custom_field_id];
    if (field) {
      const resolved = field.options[r.value] || r.value || '-';
      result[r.conversation_id][field.name] = resolved;
    }
  });
  return result;
}

// --- Commands ---

async function cmdMailboxes() {
  const conn = await getConn();
  const [rows] = await conn.query('SELECT id, name FROM mailboxes ORDER BY name');
  console.log('ID\tNAME');
  rows.forEach(r => console.log(`${r.id}\t${r.name}`));
  await conn.end();
}

async function cmdUsers() {
  const conn = await getConn();
  const [rows] = await conn.query('SELECT id, first_name, last_name, email FROM users ORDER BY first_name');
  console.log('ID\tNAME\tEMAIL');
  rows.forEach(r => console.log(`${r.id}\t${r.first_name} ${r.last_name}\t${r.email}`));
  await conn.end();
}

// Resolve customer name to custom field option ID
function resolveCustomerOptionId(cfMap, customerName) {
  const cf = cfMap.customer;
  if (!cf) return null;
  const match = Object.entries(cf.options).find(([k, v]) => v.toLowerCase() === customerName.toLowerCase());
  return match ? match[0] : null;
}

async function cmdReport(args) {
  const mailboxId = getFlag(args, '--mailbox');
  const from = getFlag(args, '--from');
  const to = getFlag(args, '--to');
  const userId = getFlag(args, '--user');
  const customerFilter = getFlag(args, '--customer');

  if (!from || !to) {
    console.error('Usage: freescout report --from YYYY-MM-DD --to YYYY-MM-DD [--mailbox ID] [--user ID] [--customer NAME]');
    process.exit(1);
  }

  const conn = await getConn();
  const cfMap = await loadCustomFieldOptions(conn);

  let query = `
    SELECT 
      t.time_spent,
      t.created_at,
      c.id as conversation_id,
      c.number as conversation_number,
      c.subject,
      c.customer_email,
      m.name as mailbox_name,
      u.first_name,
      u.last_name
    FROM timelogs t
    JOIN conversations c ON t.conversation_id = c.id
    JOIN mailboxes m ON c.mailbox_id = m.id
    JOIN users u ON t.user_id = u.id
    WHERE t.created_at >= ? AND t.created_at < DATE_ADD(?, INTERVAL 1 DAY)
  `;
  const params = [from, to];

  if (mailboxId) { query += ' AND c.mailbox_id = ?'; params.push(mailboxId); }
  if (userId) { query += ' AND t.user_id = ?'; params.push(userId); }
  if (customerFilter && cfMap.customer) {
    const optId = resolveCustomerOptionId(cfMap, customerFilter);
    if (!optId) {
      const available = Object.values(cfMap.customer.options).join(', ');
      console.error(`Customer "${customerFilter}" not found. Available: ${available}`);
      await conn.end();
      process.exit(1);
    }
    query += ' AND c.id IN (SELECT conversation_id FROM conversation_custom_field WHERE custom_field_id = ? AND value = ?)';
    params.push(cfMap.customer.id, optId);
  }

  query += ' ORDER BY t.created_at';

  const [rows] = await conn.query(query, params);

  if (rows.length === 0) {
    console.log('No timelogs found for this period.');
    await conn.end();
    return;
  }

  const convIds = [...new Set(rows.map(r => r.conversation_id))];
  const cfValues = await getConversationCustomFields(conn, convIds, cfMap);

  console.log('DATE\tCONV#\tSUBJECT\tCUSTOMER\tWEBSITE\tUSER\tHOURS');
  let totalSeconds = 0;
  rows.forEach(r => {
    const date = new Date(r.created_at).toISOString().slice(0, 10);
    const hours = formatHours(r.time_spent);
    totalSeconds += r.time_spent;
    const cf = cfValues[r.conversation_id] || {};
    console.log(`${date}\t#${r.conversation_number}\t${r.subject || '(no subject)'}\t${cf.customer || '-'}\t${cf.website || '-'}\t${r.first_name} ${r.last_name}\t${hours}`);
  });
  console.log(`\nTotal: ${formatHours(totalSeconds)} hours (${rows.length} entries)`);

  await conn.end();
}

async function cmdExcel(args) {
  const mailboxId = getFlag(args, '--mailbox');
  const from = getFlag(args, '--from');
  const to = getFlag(args, '--to');
  const userId = getFlag(args, '--user');
  const customerFilter = getFlag(args, '--customer');
  const output = getFlag(args, '--output') || `invoice-${from}-${to}.xlsx`;

  if (!from || !to) {
    console.error('Usage: freescout excel --from YYYY-MM-DD --to YYYY-MM-DD [--mailbox ID] [--user ID] [--customer NAME] [--output file.xlsx]');
    process.exit(1);
  }

  const conn = await getConn();
  const cfMap = await loadCustomFieldOptions(conn);

  let query = `
    SELECT 
      t.time_spent,
      t.created_at,
      c.id as conversation_id,
      c.number as conversation_number,
      c.subject,
      c.customer_email
    FROM timelogs t
    JOIN conversations c ON t.conversation_id = c.id
    JOIN mailboxes m ON c.mailbox_id = m.id
    JOIN users u ON t.user_id = u.id
    WHERE t.created_at >= ? AND t.created_at < DATE_ADD(?, INTERVAL 1 DAY)
  `;
  const params = [from, to];

  if (mailboxId) { query += ' AND c.mailbox_id = ?'; params.push(mailboxId); }
  if (userId) { query += ' AND t.user_id = ?'; params.push(userId); }
  if (customerFilter && cfMap.customer) {
    const optId = resolveCustomerOptionId(cfMap, customerFilter);
    if (!optId) {
      const available = Object.values(cfMap.customer.options).join(', ');
      console.error(`Customer "${customerFilter}" not found. Available: ${available}`);
      await conn.end();
      process.exit(1);
    }
    query += ' AND c.id IN (SELECT conversation_id FROM conversation_custom_field WHERE custom_field_id = ? AND value = ?)';
    params.push(cfMap.customer.id, optId);
  }

  query += ' ORDER BY t.created_at';

  const [rows] = await conn.query(query, params);

  if (rows.length === 0) {
    console.log('No timelogs found for this period.');
    await conn.end();
    return;
  }

  const convIds = [...new Set(rows.map(r => r.conversation_id))];
  const cfValues = await getConversationCustomFields(conn, convIds, cfMap);
  await conn.end();

  // Group by conversation
  const byConv = {};
  rows.forEach(r => {
    const key = r.conversation_number;
    if (!byConv[key]) {
      const cf = cfValues[r.conversation_id] || {};
      byConv[key] = {
        number: r.conversation_number,
        subject: r.subject || '(no subject)',
        customer: cf.customer || '-',
        website: cf.website || '-',
        totalSeconds: 0,
      };
    }
    byConv[key].totalSeconds += r.time_spent;
  });

  // Build Excel
  const wb = new ExcelJS.Workbook();
  const ws = wb.addWorksheet('Time Report');

  ws.columns = [
    { header: 'Conv #', key: 'number', width: 10 },
    { header: 'Subject', key: 'subject', width: 40 },
    { header: 'Customer', key: 'customer', width: 25 },
    { header: 'Website', key: 'website', width: 25 },
    { header: 'Hours', key: 'hours', width: 10 },
  ];

  ws.getRow(1).font = { bold: true };
  ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };

  let totalSeconds = 0;
  Object.values(byConv).forEach(conv => {
    totalSeconds += conv.totalSeconds;
    ws.addRow({
      number: `#${conv.number}`,
      subject: conv.subject,
      customer: conv.customer,
      website: conv.website,
      hours: formatHours(conv.totalSeconds),
    });
  });

  const totalRow = ws.addRow({ number: '', subject: '', customer: '', website: 'TOTAL', hours: formatHours(totalSeconds) });
  totalRow.font = { bold: true };

  await wb.xlsx.writeFile(output);
  console.log(`Written: ${output}`);
  console.log(`${Object.keys(byConv).length} conversations, ${formatHours(totalSeconds)} hours total`);
}

// --- Helpers ---

function getFlag(args, flag) {
  const idx = args.indexOf(flag);
  if (idx === -1) return null;
  return args[idx + 1] || null;
}

// --- Main ---

const [cmd, ...args] = process.argv.slice(2);

const commands_map = { mailboxes: cmdMailboxes, users: cmdUsers, report: cmdReport, excel: cmdExcel };

if (!cmd || !commands_map[cmd]) {
  console.log(`Usage: freescout <command> [args]

Commands:
  mailboxes                          List mailboxes
  users                              List users
  report --from DATE --to DATE       Show time report (tab-separated)
    [--mailbox ID] [--user ID] [--customer NAME]
  excel --from DATE --to DATE        Generate invoice Excel
    [--mailbox ID] [--user ID] [--customer NAME] [--output file.xlsx]`);
  process.exit(0);
}

commands_map[cmd](args).catch(e => { console.error(e.message); process.exit(1); });
