const express   = require('express');
const { query, queryOne, queryResult, exec } = require('../models/db');
const { authMiddleware, teamManagerMiddleware } = require('../middleware/auth');
const multer    = require('multer');
const { parse: csvParse } = require('csv-parse/sync');
const upload    = multer({ storage: multer.memoryStorage(), limits: { fileSize: 2 * 1024 * 1024 } });

const R = (schema, type, id) => `${schema}:${type}:${id}`;

module.exports = function(io) {

const router = express.Router();

// ── Event notification helper ─────────────────────────────────────────────────
// Posts a plain system message to each assigned user group's DM channel
// when an event is created or updated.

async function sendEventMessage(schema, dmGroupId, actorId, content) {
  const r = await queryResult(schema,
    "INSERT INTO messages (group_id,user_id,content,type) VALUES ($1,$2,$3,'system') RETURNING id",
    [dmGroupId, actorId, content]
  );
  const msg = await queryOne(schema, `
    SELECT m.*, u.name AS user_name, u.display_name AS user_display_name,
      u.avatar AS user_avatar, u.role AS user_role, u.status AS user_status,
      u.hide_admin_tag AS user_hide_admin_tag, u.about_me AS user_about_me, u.allow_dm AS user_allow_dm
    FROM messages m JOIN users u ON m.user_id = u.id WHERE m.id = $1
  `, [r.rows[0].id]);
  if (msg) { msg.reactions = []; io.to(R(schema, 'group', dmGroupId)).emit('message:new', msg); }
}

async function postEventNotification(schema, eventId, actorId) {
  try {
    const event = await queryOne(schema, 'SELECT * FROM events WHERE id=$1', [eventId]);
    if (!event) return;
    const dateStr = new Date(event.start_at).toLocaleDateString('en-US', { weekday:'short', month:'short', day:'numeric' });
    const groups = await query(schema, `
      SELECT ug.dm_group_id FROM event_user_groups eug
      JOIN user_groups ug ON ug.id = eug.user_group_id
      WHERE eug.event_id = $1 AND ug.dm_group_id IS NOT NULL
    `, [eventId]);
    for (const { dm_group_id } of groups)
      await sendEventMessage(schema, dm_group_id, actorId, `📅 Event added: "${event.title}" on ${dateStr}`);
  } catch (e) {
    console.error('[Schedule] postEventNotification error:', e.message);
  }
}

// ── Helpers ───────────────────────────────────────────────────────────────────

async function isToolManagerFn(schema, user) {
  if (user.role === 'admin' || user.role === 'manager') return true;
  const tm = await queryOne(schema, "SELECT value FROM settings WHERE key='team_tool_managers'");
  const gm = await queryOne(schema, "SELECT value FROM settings WHERE key='team_group_managers'");
  const groupIds = [...new Set([...JSON.parse(tm?.value||'[]'), ...JSON.parse(gm?.value||'[]')])];
  if (!groupIds.length) return false;
  const ph = groupIds.map((_,i) => `$${i+2}`).join(',');
  return !!(await queryOne(schema, `SELECT 1 FROM user_group_members WHERE user_id=$1 AND user_group_id IN (${ph})`, [user.id, ...groupIds]));
}

async function canViewEvent(schema, event, userId, isToolManager) {
  if (isToolManager || event.is_public) return true;
  const assigned = await queryOne(schema, `
    SELECT 1 FROM event_user_groups eug
    JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
    WHERE eug.event_id=$1 AND ugm.user_id=$2
  `, [event.id, userId]);
  return !!assigned;
}

async function enrichEvent(schema, event) {
  event.event_type = event.event_type_id
    ? await queryOne(schema, 'SELECT * FROM event_types WHERE id=$1', [event.event_type_id])
    : null;
  // recurrence_rule is JSONB in Postgres — already parsed, no need to JSON.parse
  event.user_groups = await query(schema, `
    SELECT ug.id, ug.name FROM event_user_groups eug
    JOIN user_groups ug ON ug.id=eug.user_group_id WHERE eug.event_id=$1
  `, [event.id]);
  return event;
}

async function applyEventUpdate(schema, eventId, fields, userGroupIds) {
  const { title, eventTypeId, startAt, endAt, allDay, location, description, isPublic, trackAvailability, recurrenceRule, origEvent } = fields;
  await exec(schema, `
    UPDATE events SET
      title               = COALESCE($1, title),
      event_type_id       = $2,
      start_at            = COALESCE($3, start_at),
      end_at              = COALESCE($4, end_at),
      all_day             = COALESCE($5, all_day),
      location            = $6,
      description         = $7,
      is_public           = COALESCE($8, is_public),
      track_availability  = COALESCE($9, track_availability),
      recurrence_rule     = $10,
      updated_at          = NOW()
    WHERE id = $11
  `, [
    title?.trim() || null,
    eventTypeId !== undefined ? (eventTypeId || null) : origEvent.event_type_id,
    startAt || null,
    endAt   || null,
    allDay !== undefined ? allDay : null,
    location    !== undefined ? (location    || null) : origEvent.location,
    description !== undefined ? (description || null) : origEvent.description,
    isPublic           !== undefined ? isPublic           : null,
    trackAvailability  !== undefined ? trackAvailability  : null,
    recurrenceRule !== undefined ? recurrenceRule : origEvent.recurrence_rule,
    eventId,
  ]);
  if (Array.isArray(userGroupIds)) {
    await exec(schema, 'DELETE FROM event_user_groups WHERE event_id=$1', [eventId]);
    for (const ugId of userGroupIds)
      await exec(schema, 'INSERT INTO event_user_groups (event_id,user_group_id) VALUES ($1,$2) ON CONFLICT DO NOTHING', [eventId, ugId]);
  }
}

// ── Event Types ───────────────────────────────────────────────────────────────

router.get('/event-types', authMiddleware, async (req, res) => {
  try {
    const eventTypes = await query(req.schema, 'SELECT * FROM event_types ORDER BY is_default DESC, name ASC');
    res.json({ eventTypes });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.post('/event-types', authMiddleware, teamManagerMiddleware, async (req, res) => {
  const { name, colour, defaultUserGroupId, defaultDurationHrs } = req.body;
  if (!name?.trim()) return res.status(400).json({ error: 'Name required' });
  try {
    if (await queryOne(req.schema, 'SELECT id FROM event_types WHERE LOWER(name)=LOWER($1)', [name.trim()]))
      return res.status(400).json({ error: 'Event type with that name already exists' });
    const r = await queryResult(req.schema,
      'INSERT INTO event_types (name,colour,default_user_group_id,default_duration_hrs) VALUES ($1,$2,$3,$4) RETURNING id',
      [name.trim(), colour||'#6366f1', defaultUserGroupId||null, defaultDurationHrs||1.0]
    );
    res.json({ eventType: await queryOne(req.schema, 'SELECT * FROM event_types WHERE id=$1', [r.rows[0].id]) });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.patch('/event-types/:id', authMiddleware, teamManagerMiddleware, async (req, res) => {
  try {
    const et = await queryOne(req.schema, 'SELECT * FROM event_types WHERE id=$1', [req.params.id]);
    if (!et) return res.status(404).json({ error: 'Not found' });
    if (et.is_protected) return res.status(403).json({ error: 'Cannot edit a protected event type' });
    const { name, colour, defaultUserGroupId, defaultDurationHrs } = req.body;
    if (name && name.trim() !== et.name) {
      if (await queryOne(req.schema, 'SELECT id FROM event_types WHERE LOWER(name)=LOWER($1) AND id!=$2', [name.trim(), et.id]))
        return res.status(400).json({ error: 'Name already in use' });
    }
    await exec(req.schema, `
      UPDATE event_types SET
        name                 = COALESCE($1, name),
        colour               = COALESCE($2, colour),
        default_user_group_id = $3,
        default_duration_hrs = COALESCE($4, default_duration_hrs)
      WHERE id=$5
    `, [name?.trim()||null, colour||null, defaultUserGroupId??et.default_user_group_id, defaultDurationHrs||null, et.id]);
    res.json({ eventType: await queryOne(req.schema, 'SELECT * FROM event_types WHERE id=$1', [et.id]) });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.delete('/event-types/:id', authMiddleware, teamManagerMiddleware, async (req, res) => {
  try {
    const et = await queryOne(req.schema, 'SELECT * FROM event_types WHERE id=$1', [req.params.id]);
    if (!et) return res.status(404).json({ error: 'Not found' });
    if (et.is_default || et.is_protected) return res.status(403).json({ error: 'Cannot delete a protected event type' });
    await exec(req.schema, 'UPDATE events SET event_type_id=NULL WHERE event_type_id=$1', [et.id]);
    await exec(req.schema, 'DELETE FROM event_types WHERE id=$1', [et.id]);
    res.json({ success: true });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ── User's own groups (for regular users creating events) ─────────────────────

router.get('/my-groups', authMiddleware, async (req, res) => {
  try {
    const groups = await query(req.schema, `
      SELECT ug.id, ug.name FROM user_groups ug
      JOIN user_group_members ugm ON ugm.user_group_id = ug.id
      WHERE ugm.user_id = $1
      ORDER BY ug.name ASC
    `, [req.user.id]);
    res.json({ groups });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ── Events ────────────────────────────────────────────────────────────────────

router.get('/', authMiddleware, async (req, res) => {
  try {
    const itm = await isToolManagerFn(req.schema, req.user);
    const { from, to } = req.query;
    let sql = 'SELECT * FROM events WHERE 1=1';
    const params = [];
    let pi = 1;
    if (from) { sql += ` AND end_at >= $${pi++}`;   params.push(from); }
    if (to)   { sql += ` AND start_at <= $${pi++}`; params.push(to); }
    sql += ' ORDER BY start_at ASC';
    const rawEvents = await query(req.schema, sql, params);
    const events = [];
    for (const e of rawEvents) {
      if (!(await canViewEvent(req.schema, e, req.user.id, itm))) continue;
      await enrichEvent(req.schema, e);
      const mine = await queryOne(req.schema, 'SELECT response FROM event_availability WHERE event_id=$1 AND user_id=$2', [e.id, req.user.id]);
      e.my_response = mine?.response || null;
      events.push(e);
    }
    res.json({ events });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.get('/me/pending', authMiddleware, async (req, res) => {
  try {
    const pending = await query(req.schema, `
      SELECT DISTINCT e.* FROM events e
      JOIN event_user_groups eug ON eug.event_id=e.id
      JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
      WHERE ugm.user_id=$1 AND e.track_availability=TRUE
        AND e.end_at >= NOW()
        AND NOT EXISTS (SELECT 1 FROM event_availability ea WHERE ea.event_id=e.id AND ea.user_id=$1)
      ORDER BY e.start_at ASC
    `, [req.user.id]);
    const result = [];
    for (const e of pending) result.push(await enrichEvent(req.schema, e));
    res.json({ events: result });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.get('/:id', authMiddleware, async (req, res) => {
  try {
    const event = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [req.params.id]);
    if (!event) return res.status(404).json({ error: 'Not found' });
    const itm = await isToolManagerFn(req.schema, req.user);
    if (!(await canViewEvent(req.schema, event, req.user.id, itm))) return res.status(403).json({ error: 'Access denied' });
    await enrichEvent(req.schema, event);
    const isMember = !itm && !!(await queryOne(req.schema, `
      SELECT 1 FROM event_user_groups eug
      JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
      WHERE eug.event_id=$1 AND ugm.user_id=$2
    `, [event.id, req.user.id]));
    if (event.track_availability && (itm || isMember)) {
      event.availability = await query(req.schema, `
        SELECT ea.response, ea.note, ea.updated_at, u.id AS user_id, u.name, u.display_name, u.avatar
        FROM event_availability ea JOIN users u ON u.id=ea.user_id WHERE ea.event_id=$1
      `, [req.params.id]);
      if (itm) {
        const assignedIds = (await query(req.schema, `
          SELECT DISTINCT ugm.user_id FROM event_user_groups eug
          JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id WHERE eug.event_id=$1
        `, [req.params.id])).map(r => r.user_id);
        const respondedIds = new Set(event.availability.map(r => r.user_id));
        event.no_response_count = assignedIds.filter(id => !respondedIds.has(id)).length;
      }
    }
    const mine = await queryOne(req.schema, 'SELECT response, note FROM event_availability WHERE event_id=$1 AND user_id=$2', [req.params.id, req.user.id]);
    event.my_response = mine?.response || null;
    event.my_note = mine?.note || null;
    res.json({ event });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.post('/', authMiddleware, async (req, res) => {
  const { title, eventTypeId, startAt, endAt, allDay, location, description, isPublic, trackAvailability, userGroupIds=[], recurrenceRule } = req.body;
  if (!title?.trim()) return res.status(400).json({ error: 'Title required' });
  if (!startAt || !endAt) return res.status(400).json({ error: 'Start and end time required' });
  try {
    const itm = await isToolManagerFn(req.schema, req.user);
    const groupIds = Array.isArray(userGroupIds) ? userGroupIds : [];
    if (!itm) {
      // Regular users: must select at least one group they belong to; event always private
      if (!groupIds.length) return res.status(400).json({ error: 'Select at least one group' });
      for (const ugId of groupIds) {
        const member = await queryOne(req.schema, 'SELECT 1 FROM user_group_members WHERE user_id=$1 AND user_group_id=$2', [req.user.id, ugId]);
        if (!member) return res.status(403).json({ error: 'You can only assign groups you belong to' });
      }
    }
    const effectiveIsPublic = itm ? (isPublic !== false) : false;
    const r = await queryResult(req.schema, `
      INSERT INTO events (title,event_type_id,start_at,end_at,all_day,location,description,is_public,track_availability,recurrence_rule,created_by)
      VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) RETURNING id
    `, [title.trim(), eventTypeId||null, startAt, endAt, !!allDay, location||null, description||null,
        effectiveIsPublic, !!trackAvailability, recurrenceRule||null, req.user.id]);
    const eventId = r.rows[0].id;
    for (const ugId of groupIds)
      await exec(req.schema, 'INSERT INTO event_user_groups (event_id,user_group_id) VALUES ($1,$2) ON CONFLICT DO NOTHING', [eventId, ugId]);
    if (groupIds.length > 0)
      await postEventNotification(req.schema, eventId, req.user.id);
    const event = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [eventId]);
    res.json({ event: await enrichEvent(req.schema, event) });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.patch('/:id', authMiddleware, async (req, res) => {
  try {
    const event = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [req.params.id]);
    if (!event) return res.status(404).json({ error: 'Not found' });
    const itm = await isToolManagerFn(req.schema, req.user);
    if (!itm && event.created_by !== req.user.id) return res.status(403).json({ error: 'Access denied' });
    let { title, eventTypeId, startAt, endAt, allDay, location, description, isPublic, trackAvailability, userGroupIds, recurrenceRule, recurringScope } = req.body;
    if (!itm) {
      // Regular users editing their own event: force private, validate group membership
      isPublic = false;
      if (Array.isArray(userGroupIds)) {
        if (!userGroupIds.length) return res.status(400).json({ error: 'Select at least one group' });
        for (const ugId of userGroupIds) {
          const member = await queryOne(req.schema, 'SELECT 1 FROM user_group_members WHERE user_id=$1 AND user_group_id=$2', [req.user.id, ugId]);
          if (!member) return res.status(403).json({ error: 'You can only assign groups you belong to' });
        }
        // Preserve any existing groups on this event that the user doesn't belong to
        // (e.g. groups added by an admin) — silently merge them back into the submitted list
        const existingGroupIds = (await query(req.schema, 'SELECT user_group_id FROM event_user_groups WHERE event_id=$1', [req.params.id])).map(r => r.user_group_id);
        const submittedSet = new Set(userGroupIds.map(Number));
        for (const gid of existingGroupIds) {
          if (submittedSet.has(gid)) continue;
          const member = await queryOne(req.schema, 'SELECT 1 FROM user_group_members WHERE user_id=$1 AND user_group_id=$2', [req.user.id, gid]);
          if (!member) userGroupIds.push(gid);
        }
      }
    }
    const fields = { title, eventTypeId, startAt, endAt, allDay, location, description, isPublic, trackAvailability, recurrenceRule, origEvent: event };

    // Capture group/DM mapping before applyEventUpdate modifies event_user_groups
    const prevGroupRows = await query(req.schema, `
      SELECT eug.user_group_id, ug.dm_group_id FROM event_user_groups eug
      JOIN user_groups ug ON ug.id=eug.user_group_id
      WHERE eug.event_id=$1 AND ug.dm_group_id IS NOT NULL
    `, [req.params.id]);
    const prevGroupIdSet = new Set(prevGroupRows.map(r => r.user_group_id));

    await applyEventUpdate(req.schema, req.params.id, fields, userGroupIds);

    // Recurring future scope — update this and all future occurrences
    if (recurringScope === 'future' && event.recurrence_rule) {
      const futureEvents = await query(req.schema, `
        SELECT id FROM events WHERE id!=$1 AND created_by=$2 AND recurrence_rule IS NOT NULL
          AND start_at >= $3 AND title=$4
      `, [req.params.id, event.created_by, event.start_at, event.title]);
      for (const fe of futureEvents)
        await applyEventUpdate(req.schema, fe.id, fields, userGroupIds);
    }
    // Recurring all scope — update every occurrence
    if (recurringScope === 'all' && event.recurrence_rule) {
      const allEvents = await query(req.schema, `
        SELECT id FROM events WHERE id!=$1 AND created_by=$2 AND recurrence_rule IS NOT NULL AND title=$3
      `, [req.params.id, event.created_by, event.title]);
      for (const ae of allEvents)
        await applyEventUpdate(req.schema, ae.id, fields, userGroupIds);
    }

    // Clean up availability for users removed from groups
    if (Array.isArray(userGroupIds)) {
      const prevGroupIds = (await query(req.schema, 'SELECT user_group_id FROM event_user_groups WHERE event_id=$1', [req.params.id])).map(r => r.user_group_id);
      const newGroupSet  = new Set(userGroupIds.map(Number));
      const removedGroupIds = prevGroupIds.filter(id => !newGroupSet.has(id));
      for (const removedGid of removedGroupIds) {
        const removedUids = (await query(req.schema, 'SELECT user_id FROM user_group_members WHERE user_group_id=$1', [removedGid])).map(r => r.user_id);
        for (const uid of removedUids) {
          if (newGroupSet.size > 0) {
            const ph = [...newGroupSet].map((_,i) => `$${i+2}`).join(',');
            const stillAssigned = await queryOne(req.schema, `SELECT 1 FROM user_group_members WHERE user_id=$1 AND user_group_id IN (${ph})`, [uid, ...[...newGroupSet]]);
            if (stillAssigned) continue;
          }
          await exec(req.schema, 'DELETE FROM event_availability WHERE event_id=$1 AND user_id=$2', [req.params.id, uid]);
        }
      }
    }

    const updated = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [req.params.id]);

    // Targeted notifications — only for meaningful changes, only to relevant groups
    try {
      const finalGroupRows = await query(req.schema, `
        SELECT eug.user_group_id, ug.dm_group_id FROM event_user_groups eug
        JOIN user_groups ug ON ug.id=eug.user_group_id
        WHERE eug.event_id=$1 AND ug.dm_group_id IS NOT NULL
      `, [req.params.id]);
      const allDmIds = finalGroupRows.map(r => r.dm_group_id);
      const dateStr = new Date(updated.start_at).toLocaleDateString('en-US', { weekday:'short', month:'short', day:'numeric' });

      // Newly added groups → "Event added" only to those groups
      if (Array.isArray(userGroupIds)) {
        for (const { user_group_id, dm_group_id } of finalGroupRows) {
          if (!prevGroupIdSet.has(user_group_id))
            await sendEventMessage(req.schema, dm_group_id, req.user.id, `📅 Event added: "${updated.title}" on ${dateStr}`);
        }
      }

      // Date/time changed → "Event updated" to all groups
      const timeChanged = (startAt && new Date(startAt).getTime() !== new Date(event.start_at).getTime())
                       || (endAt   && new Date(endAt).getTime()   !== new Date(event.end_at).getTime())
                       || (allDay  !== undefined && !!allDay !== !!event.all_day);
      if (timeChanged) {
        for (const dmId of allDmIds)
          await sendEventMessage(req.schema, dmId, req.user.id, `📅 Event updated: "${updated.title}" on ${dateStr}`);
      }

      // Location changed → "Location updated" to all groups
      const locationChanged = location !== undefined && (location || null) !== (event.location || null);
      if (locationChanged) {
        const locContent = updated.location
          ? `📍 Location updated to "${updated.location}": "${updated.title}" on ${dateStr}`
          : `📍 Location removed: "${updated.title}" on ${dateStr}`;
        for (const dmId of allDmIds)
          await sendEventMessage(req.schema, dmId, req.user.id, locContent);
      }
    } catch (e) {
      console.error('[Schedule] event update notification error:', e.message);
    }

    res.json({ event: await enrichEvent(req.schema, updated) });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.delete('/:id', authMiddleware, async (req, res) => {
  try {
    const event = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [req.params.id]);
    if (!event) return res.status(404).json({ error: 'Not found' });
    const itm = await isToolManagerFn(req.schema, req.user);
    if (!itm && event.created_by !== req.user.id) return res.status(403).json({ error: 'Access denied' });
    const { recurringScope, occurrenceStart } = req.body || {};
    const pad = n => String(n).padStart(2, '0');

    if (event.recurrence_rule && recurringScope === 'all') {
      // Delete the single base row — all virtual occurrences disappear with it
      await exec(req.schema, 'DELETE FROM events WHERE id=$1', [req.params.id]);

    } else if (event.recurrence_rule && recurringScope === 'future') {
      // Truncate the series so it ends before this occurrence
      const occDate = new Date(occurrenceStart || event.start_at);
      if (occDate <= new Date(event.start_at)) {
        // Occurrence is at or before the base start — delete the whole series
        await exec(req.schema, 'DELETE FROM events WHERE id=$1', [req.params.id]);
      } else {
        const endBefore = new Date(occDate);
        endBefore.setDate(endBefore.getDate() - 1);
        const rule = { ...event.recurrence_rule };
        rule.ends    = 'on';
        rule.endDate = `${endBefore.getFullYear()}-${pad(endBefore.getMonth()+1)}-${pad(endBefore.getDate())}`;
        delete rule.endCount;
        await exec(req.schema, 'UPDATE events SET recurrence_rule=$1 WHERE id=$2', [JSON.stringify(rule), req.params.id]);
      }

    } else if (event.recurrence_rule && recurringScope === 'this') {
      // Add occurrence date to exceptions — base row and other occurrences are untouched
      const occDate = new Date(occurrenceStart || event.start_at);
      const occDateStr = `${occDate.getFullYear()}-${pad(occDate.getMonth()+1)}-${pad(occDate.getDate())}`;
      const rule = { ...event.recurrence_rule };
      const existing = Array.isArray(rule.exceptions) ? rule.exceptions : [];
      rule.exceptions = [...existing.filter(d => d !== occDateStr), occDateStr];
      await exec(req.schema, 'UPDATE events SET recurrence_rule=$1 WHERE id=$2', [JSON.stringify(rule), req.params.id]);

    } else {
      // Non-recurring single delete
      await exec(req.schema, 'DELETE FROM events WHERE id=$1', [req.params.id]);
    }
    res.json({ success: true });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ── Availability ──────────────────────────────────────────────────────────────

router.put('/:id/availability', authMiddleware, async (req, res) => {
  try {
    const event = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [req.params.id]);
    if (!event) return res.status(404).json({ error: 'Not found' });
    if (!event.track_availability) return res.status(400).json({ error: 'Availability tracking not enabled' });
    const { response, note } = req.body;
    if (!['going','maybe','not_going'].includes(response)) return res.status(400).json({ error: 'Invalid response' });
    const trimmedNote = note ? String(note).trim().slice(0, 20) : null;
    const itm = await isToolManagerFn(req.schema, req.user);
    const inGroup = await queryOne(req.schema, `
      SELECT 1 FROM event_user_groups eug JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
      WHERE eug.event_id=$1 AND ugm.user_id=$2
    `, [event.id, req.user.id]);
    if (!inGroup && !itm) return res.status(403).json({ error: 'You are not assigned to this event' });
    await exec(req.schema, `
      INSERT INTO event_availability (event_id,user_id,response,note,updated_at) VALUES ($1,$2,$3,$4,NOW())
      ON CONFLICT (event_id,user_id) DO UPDATE SET response=$3, note=$4, updated_at=NOW()
    `, [event.id, req.user.id, response, trimmedNote]);
    res.json({ success: true, response, note: trimmedNote });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.patch('/:id/availability/note', authMiddleware, async (req, res) => {
  try {
    const existing = await queryOne(req.schema, 'SELECT response FROM event_availability WHERE event_id=$1 AND user_id=$2', [req.params.id, req.user.id]);
    if (!existing) return res.status(404).json({ error: 'No availability response found' });
    const trimmedNote = req.body.note ? String(req.body.note).trim().slice(0, 20) : null;
    await exec(req.schema, 'UPDATE event_availability SET note=$1, updated_at=NOW() WHERE event_id=$2 AND user_id=$3', [trimmedNote, req.params.id, req.user.id]);
    res.json({ success: true, note: trimmedNote });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.delete('/:id/availability', authMiddleware, async (req, res) => {
  try {
    await exec(req.schema, 'DELETE FROM event_availability WHERE event_id=$1 AND user_id=$2', [req.params.id, req.user.id]);
    res.json({ success: true });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

router.post('/me/bulk-availability', authMiddleware, async (req, res) => {
  const { responses } = req.body;
  if (!Array.isArray(responses)) return res.status(400).json({ error: 'responses array required' });
  try {
    let saved = 0;
    const itm = await isToolManagerFn(req.schema, req.user);
    for (const { eventId, response } of responses) {
      if (!['going','maybe','not_going'].includes(response)) continue;
      const event = await queryOne(req.schema, 'SELECT * FROM events WHERE id=$1', [eventId]);
      if (!event || !event.track_availability) continue;
      const inGroup = await queryOne(req.schema, `
        SELECT 1 FROM event_user_groups eug JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
        WHERE eug.event_id=$1 AND ugm.user_id=$2
      `, [eventId, req.user.id]);
      if (!inGroup && !itm) continue;
      await exec(req.schema, `
        INSERT INTO event_availability (event_id,user_id,response,updated_at) VALUES ($1,$2,$3,NOW())
        ON CONFLICT (event_id,user_id) DO UPDATE SET response=$3, updated_at=NOW()
      `, [eventId, req.user.id, response]);
      saved++;
    }
    res.json({ success: true, saved });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ── CSV Import ────────────────────────────────────────────────────────────────

router.post('/import/preview', authMiddleware, teamManagerMiddleware, upload.single('file'), async (req, res) => {
  if (!req.file) return res.status(400).json({ error: 'No file uploaded' });
  try {
    const rows = csvParse(req.file.buffer.toString('utf8'), { columns:true, skip_empty_lines:true, trim:true });
    const results = await Promise.all(rows.map(async (row, i) => {
      const title     = row['Event Title'] || row['event_title'] || row['title'] || '';
      const startDate = row['start_date']  || row['Start Date']  || '';
      const startTime = row['start_time']  || row['Start Time']  || '09:00';
      const location  = row['event_location'] || row['location'] || '';
      const typeName  = row['event_type']  || row['Event Type']  || 'Default';
      const durHrs    = parseFloat(row['default_duration'] || row['duration'] || '1') || 1;
      if (!title || !startDate) return { row:i+1, title, error:'Missing title or start date', duplicate:false };
      const startAt = `${startDate}T${startTime.padStart(5,'0')}:00`;
      const endMs   = new Date(startAt).getTime() + durHrs * 3600000;
      const endAt   = isNaN(endMs) ? startAt : new Date(endMs).toISOString().slice(0,19);
      const dup     = await queryOne(req.schema, 'SELECT id,title FROM events WHERE title=$1 AND start_at=$2', [title, startAt]);
      return { row:i+1, title, startAt, endAt, location, typeName, durHrs, duplicate:!!dup, duplicateId:dup?.id, error:null };
    }));
    res.json({ rows: results });
  } catch (e) { res.status(400).json({ error: 'CSV parse error: ' + e.message }); }
});

router.post('/import/confirm', authMiddleware, teamManagerMiddleware, async (req, res) => {
  const { rows } = req.body;
  if (!Array.isArray(rows)) return res.status(400).json({ error: 'rows array required' });
  try {
    let imported = 0;
    const colours = ['#ef4444','#f97316','#eab308','#22c55e','#06b6d4','#3b82f6','#8b5cf6','#ec4899'];
    for (const row of rows) {
      if (row.error || row.skip) continue;
      let typeId = null;
      if (row.typeName) {
        let et = await queryOne(req.schema, 'SELECT id FROM event_types WHERE LOWER(name)=LOWER($1)', [row.typeName]);
        if (!et) {
          const usedColours = (await query(req.schema, 'SELECT colour FROM event_types')).map(r => r.colour);
          const colour = colours.find(c => !usedColours.includes(c)) || '#' + Math.floor(Math.random()*0xffffff).toString(16).padStart(6,'0');
          const cr = await queryResult(req.schema, 'INSERT INTO event_types (name,colour) VALUES ($1,$2) RETURNING id', [row.typeName, colour]);
          typeId = cr.rows[0].id;
        } else { typeId = et.id; }
      }
      await exec(req.schema,
        'INSERT INTO events (title,event_type_id,start_at,end_at,location,is_public,track_availability,created_by) VALUES ($1,$2,$3,$4,$5,TRUE,FALSE,$6)',
        [row.title, typeId, row.startAt, row.endAt, row.location||null, req.user.id]
      );
      imported++;
    }
    res.json({ success: true, imported });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

return router;
}; // end module.exports
