// Booking sheet integration
// Manages bed assignments on a Google Sheets booking sheet
// Ported from CCG's lib/booking-sheet.ts, adapted for week-based columns

const fs = require('fs');

let sheetsClient = null;

// Accommodation criteria mapping — maps accommodation_type to sheet matching rules
const ACCOMMODATION_CRITERIA = {
  'ch-multi': {
    venue: 'Commons Hub',
    bedTypes: ['Bunk up', 'Bunk down', 'Single'],
  },
  'ch-double': {
    venue: 'Commons Hub',
    bedTypes: ['Double'],
  },
  'hh-living': {
    venue: 'Herrnhof Villa',
    bedTypes: ['Living room', 'Sofa bed', 'Daybed'],
  },
  'hh-triple': {
    venue: 'Herrnhof Villa',
    bedTypes: ['Triple'],
  },
  'hh-twin': {
    venue: 'Herrnhof Villa',
    bedTypes: ['Twin', 'Double (separate)'],
  },
  'hh-single': {
    venue: 'Herrnhof Villa',
    bedTypes: ['Single'],
  },
  'hh-couple': {
    venue: 'Herrnhof Villa',
    bedTypes: ['Double (shared)', 'Double', 'Couple'],
  },
};

// Week column headers expected in the sheet
const WEEK_COLUMNS = ['Week 1', 'Week 2', 'Week 3', 'Week 4'];

function getCredentials() {
  const filePath = process.env.GOOGLE_SERVICE_ACCOUNT_FILE;
  if (filePath) {
    try {
      return JSON.parse(fs.readFileSync(filePath, 'utf8'));
    } catch (err) {
      console.error('[Booking Sheet] Failed to read credentials file:', err.message);
      return null;
    }
  }

  const raw = process.env.GOOGLE_SERVICE_ACCOUNT;
  if (!raw) return null;
  try {
    return JSON.parse(raw.trim());
  } catch {
    console.error('[Booking Sheet] Failed to parse service account JSON');
    return null;
  }
}

async function getSheetsClient() {
  if (sheetsClient) return sheetsClient;

  const creds = getCredentials();
  if (!creds) return null;

  const { google } = require('googleapis');
  const auth = new google.auth.GoogleAuth({
    credentials: creds,
    scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  });
  sheetsClient = google.sheets({ version: 'v4', auth });
  return sheetsClient;
}

/**
 * Read and parse the booking sheet.
 * Expected structure per venue section:
 *   Row: "Commons Hub" or "Herrnhof Villa" (venue header)
 *   Row: Room | Bed Type | Week 1 | Week 2 | Week 3 | Week 4 (column headers)
 *   Row: 5   | Bunk up  |        |        |        |         (bed rows)
 *   ...
 *   Empty row (section separator)
 *
 * Returns array of bed objects:
 *   { venue, room, bedType, rowIndex, weekColumns: { 'Week 1': colIndex, ... }, occupancy: { 'Week 1': 'Guest Name' | null, ... } }
 */
async function parseBookingSheet() {
  const sheets = await getSheetsClient();
  if (!sheets) {
    console.log('[Booking Sheet] No credentials configured — skipping');
    return null;
  }

  const sheetId = process.env.BOOKING_SHEET_ID || process.env.GOOGLE_SHEET_ID;
  const sheetName = process.env.BOOKING_SHEET_TAB || 'Booking Sheet';

  const response = await sheets.spreadsheets.values.get({
    spreadsheetId: sheetId,
    range: `${sheetName}!A:G`,
  });

  const rows = response.data.values || [];
  const beds = [];
  let currentVenue = null;
  let weekColIndexes = {};

  for (let i = 0; i < rows.length; i++) {
    const row = rows[i];
    if (!row || row.length === 0 || row.every(cell => !cell || !cell.toString().trim())) {
      // Empty row — reset venue context
      currentVenue = null;
      weekColIndexes = {};
      continue;
    }

    const firstCell = (row[0] || '').toString().trim();

    // Check if this is a venue header
    if (firstCell === 'Commons Hub' || firstCell === 'Herrnhof Villa') {
      currentVenue = firstCell;
      weekColIndexes = {};
      continue;
    }

    // Check if this is the column header row (contains "Room" and week columns)
    if (firstCell.toLowerCase() === 'room' && currentVenue) {
      for (let c = 0; c < row.length; c++) {
        const header = (row[c] || '').toString().trim();
        if (WEEK_COLUMNS.includes(header)) {
          weekColIndexes[header] = c;
        }
      }
      continue;
    }

    // If we have a venue and week columns, this is a bed row
    if (currentVenue && Object.keys(weekColIndexes).length > 0 && firstCell) {
      const room = firstCell;
      const bedType = (row[1] || '').toString().trim();
      if (!bedType) continue;

      const occupancy = {};
      for (const [week, colIdx] of Object.entries(weekColIndexes)) {
        const cellValue = (row[colIdx] || '').toString().trim();
        occupancy[week] = cellValue || null;
      }

      beds.push({
        venue: currentVenue,
        room,
        bedType,
        rowIndex: i,
        weekColumns: { ...weekColIndexes },
        occupancy,
      });
    }
  }

  return beds;
}

/**
 * Find an available bed matching the accommodation criteria for the given weeks.
 * A bed is "available" only if ALL requested week columns are empty.
 */
function findAvailableBed(beds, accommodationType, selectedWeeks) {
  const criteria = ACCOMMODATION_CRITERIA[accommodationType];
  if (!criteria) {
    console.error(`[Booking Sheet] Unknown accommodation type: ${accommodationType}`);
    return null;
  }

  // Map week values (week1, week2, etc.) to column headers (Week 1, Week 2, etc.)
  const weekHeaders = selectedWeeks.map(w => {
    const num = w.replace('week', '');
    return `Week ${num}`;
  });

  for (const bed of beds) {
    // Match venue
    if (bed.venue !== criteria.venue) continue;

    // Match bed type (case-insensitive partial match)
    const bedTypeLower = bed.bedType.toLowerCase();
    const matchesBedType = criteria.bedTypes.some(bt => bedTypeLower.includes(bt.toLowerCase()));
    if (!matchesBedType) continue;

    // Check all requested weeks are empty
    const allWeeksAvailable = weekHeaders.every(wh => !bed.occupancy[wh]);
    if (!allWeeksAvailable) continue;

    return bed;
  }

  return null;
}

/**
 * Assign a guest to a bed on the booking sheet.
 * Writes guest name to the selected week columns for the matched bed row.
 *
 * @param {string} guestName - Full name of the guest
 * @param {string} accommodationType - e.g. 'ch-multi', 'hh-single'
 * @param {string[]} selectedWeeks - e.g. ['week1', 'week2', 'week3']
 * @returns {object} Result with success status, venue, room, bedType
 */
async function assignBooking(guestName, accommodationType, selectedWeeks) {
  if (!accommodationType || !selectedWeeks || selectedWeeks.length === 0) {
    return { success: false, reason: 'Missing accommodation type or weeks' };
  }

  try {
    const beds = await parseBookingSheet();
    if (!beds) {
      return { success: false, reason: 'Booking sheet not configured' };
    }

    const bed = findAvailableBed(beds, accommodationType, selectedWeeks);
    if (!bed) {
      console.warn(`[Booking Sheet] No available bed for ${accommodationType}, weeks: ${selectedWeeks.join(', ')}`);
      return { success: false, reason: 'No available bed matching criteria' };
    }

    // Write guest name to the selected week columns
    const sheets = await getSheetsClient();
    const sheetId = process.env.BOOKING_SHEET_ID || process.env.GOOGLE_SHEET_ID;
    const sheetName = process.env.BOOKING_SHEET_TAB || 'Booking Sheet';

    // Convert week values to column headers
    const weekHeaders = selectedWeeks.map(w => `Week ${w.replace('week', '')}`);

    // Build batch update data
    const data = weekHeaders
      .filter(wh => bed.weekColumns[wh] !== undefined)
      .map(wh => {
        const col = bed.weekColumns[wh];
        const colLetter = String.fromCharCode(65 + col); // A=0, B=1, ...
        const rowNum = bed.rowIndex + 1; // Sheets is 1-indexed
        return {
          range: `${sheetName}!${colLetter}${rowNum}`,
          values: [[guestName]],
        };
      });

    if (data.length > 0) {
      await sheets.spreadsheets.values.batchUpdate({
        spreadsheetId: sheetId,
        resource: {
          valueInputOption: 'USER_ENTERED',
          data,
        },
      });
    }

    console.log(`[Booking Sheet] Assigned ${guestName} to ${bed.venue} Room ${bed.room} (${bed.bedType}) for weeks: ${selectedWeeks.join(', ')}`);

    return {
      success: true,
      venue: bed.venue,
      room: bed.room,
      bedType: bed.bedType,
    };
  } catch (error) {
    console.error('[Booking Sheet] Assignment failed:', error);
    return { success: false, reason: error.message };
  }
}

module.exports = { assignBooking, parseBookingSheet, findAvailableBed, ACCOMMODATION_CRITERIA };
