const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const path = require('path');
const fs = require('fs').promises;
const { configureAuth, requireAuth, optionalAuth } = require('./auth');
const { preferencesOps, favoritesOps } = require('./database');
const BibleSearchEngine = require('./search');

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(helmet({
  contentSecurityPolicy: false,
  crossOriginOpenerPolicy: false,
  crossOriginEmbedderPolicy: false,
  originAgentCluster: false
}));
app.use(cors({
  origin: process.env.FRONTEND_URL || true,
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'Cookie'],
  exposedHeaders: ['Set-Cookie']
}));
app.use(express.json());

// Configure authentication
configureAuth(app);

// Serve static files from the React build
app.use(express.static(path.join(__dirname, '../../frontend/build')));

// Bible data directories
const ESV_DATA_DIR = path.join(__dirname, '../../bible-data'); // ESV from mdbible
const NKJV_DATA_DIR = path.join(__dirname, '../../NKJV'); // NKJV local files

// Initialize search engines for each version
let esvSearchEngine = null;
let nkjvSearchEngine = null;

try {
  if (ESV_DATA_DIR) {
    esvSearchEngine = new BibleSearchEngine(ESV_DATA_DIR);
  }
} catch (error) {
  console.log('ESV search engine failed to initialize (data directory may not exist):', error.message);
}

try {
  nkjvSearchEngine = new BibleSearchEngine(NKJV_DATA_DIR);
} catch (error) {
  console.log('NKJV search engine failed to initialize:', error.message);
}

// Helper function to get data directory for version
function getDataDir(version) {
  if (version === 'esv' && esvSearchEngine) return ESV_DATA_DIR;
  if (version === 'nkjv') return NKJV_DATA_DIR;
  return esvSearchEngine ? ESV_DATA_DIR : NKJV_DATA_DIR; // default to available version
}

// Helper function to read markdown files
async function readMarkdownFile(filePath) {
  try {
    const content = await fs.readFile(filePath, 'utf-8');
    // Remove BOM if present and normalize encoding issues
    return content.replace(/^\uFEFF/, ''); // Remove UTF-8 BOM
  } catch (error) {
    throw new Error(`Failed to read file: ${filePath}`);
  }
}

// Helper function to get all books for a version
async function getBooks(version = 'esv') {
  try {
    const dataDir = getDataDir(version);
    console.log(`Attempting to read books from: ${dataDir} for version: ${version}`);

    const items = await fs.readdir(dataDir);
    console.log(`Found ${items.length} items in ${dataDir}`);

    const bookDirs = [];

    for (const item of items) {
      const itemPath = path.join(dataDir, item);
      const stat = await fs.stat(itemPath);

      if (stat.isDirectory()) {
        console.log(`Checking directory: ${item}`);
        // Check if directory contains markdown files
        try {
          const files = await fs.readdir(itemPath);
          if (files.some(file => file.endsWith('.md'))) {
            bookDirs.push(item);
            console.log(`Added book: ${item} (${files.length} files)`);
          }
        } catch (error) {
          // Skip directories we can't read
          console.log(`Could not read files in ${item}: ${error.message}`);
          continue;
        }
      }
    }

    console.log(`Found ${bookDirs.length} books for version ${version}:`, bookDirs.slice(0, 5));
    return bookDirs;
  } catch (error) {
    console.error(`Failed to read bible data directory for version ${version}:`, error.message);
    throw new Error(`Failed to read bible data directory for version ${version}`);
  }
}

// Routes
app.get('/health', (req, res) => {
  res.json({ status: 'OK', message: 'The Bible API is running' });
});

app.get('/versions', (req, res) => {
  const availableVersions = [];
  if (esvSearchEngine) availableVersions.push({ id: 'esv', name: 'ESV - English Standard Version' });
  availableVersions.push({ id: 'nkjv', name: 'NKJV - New King James Version' });

  res.json({ versions: availableVersions });
});

app.get('/books', async (req, res) => {
  try {
    const { version = 'esv' } = req.query;
    const books = await getBooks(version);
    res.json({ books, version });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/books/:book', async (req, res) => {
  try {
    const { book } = req.params;
    const { version = 'esv' } = req.query;
    const dataDir = getDataDir(version);
    const bookDir = path.join(dataDir, book);

    // Check if book directory exists
    const stat = await fs.stat(bookDir);
    if (!stat.isDirectory()) {
      return res.status(404).json({ error: `Book '${book}' not found in version '${version}'` });
    }

    // Get all chapter files
    const files = await fs.readdir(bookDir);
    const chapterFiles = files.filter(file => file.endsWith('.md')).sort();

    if (chapterFiles.length === 0) {
      return res.status(404).json({ error: `No chapters found for book '${book}' in version '${version}'` });
    }

    // Extract chapter numbers from filenames (e.g., "Chapter_01.md" -> "1")
    const chapters = chapterFiles.map(file => {
      const match = file.match(/Chapter_(\d+)\.md$/);
      return match ? parseInt(match[1], 10).toString() : null;
    }).filter(Boolean);

    res.json({ chapters, version });
  } catch (error) {
    res.status(404).json({ error: `Book '${req.params.book}' not found in version '${req.query.version || 'esv'}'` });
  }
});

app.get('/books/:book/:chapter', async (req, res) => {
  try {
    const { book, chapter } = req.params;
    const { version = 'esv' } = req.query;

    // Check if chapter already includes "Chapter_" prefix (from frontend)
    let chapterFileName;
    if (chapter.startsWith('Chapter_')) {
      chapterFileName = `${chapter}.md`;
    } else {
      // Legacy support: if just a number, format with leading zero
      const paddedChapter = chapter.padStart(2, '0');
      chapterFileName = `Chapter_${paddedChapter}.md`;
    }

    const dataDir = getDataDir(version);
    const chapterPath = path.join(dataDir, book, chapterFileName);

    const content = await readMarkdownFile(chapterPath);
    res.type('text/markdown').send(content);
  } catch (error) {
    res.status(404).json({ error: `Chapter ${req.params.chapter} not found in book '${req.params.book}' for version '${req.query.version || 'esv'}'` });
  }
});

// Search routes
app.get('/api/search', async (req, res) => {
  try {
    const { q: query, book, limit, context, version = 'esv' } = req.query;

    if (!query || query.trim().length < 2) {
      return res.status(400).json({ error: 'Query must be at least 2 characters long' });
    }

    // Get the appropriate search engine for the version
    const searchEngine = version === 'esv' && esvSearchEngine ? esvSearchEngine : nkjvSearchEngine;

    const options = {
      bookFilter: book || null,
      limit: parseInt(limit) || 50,
      includeContext: context !== 'false',
      contextSize: 2
    };

    const results = await searchEngine.search(query, options);

    res.json({
      query,
      results,
      total: results.length,
      hasMore: results.length === options.limit,
      version
    });
  } catch (error) {
    console.error('Search error:', error);
    res.status(500).json({ error: 'Search failed. Please try again.' });
  }
});

app.get('/api/search/suggestions', async (req, res) => {
  try {
    const { q: query, limit, version = 'esv' } = req.query;

    if (!query || query.trim().length < 2) {
      return res.json({ suggestions: [] });
    }

    // Get the appropriate search engine for the version
    const searchEngine = version === 'esv' && esvSearchEngine ? esvSearchEngine : nkjvSearchEngine;

    const suggestions = await searchEngine.getSearchSuggestions(query, parseInt(limit) || 10);

    res.json({ suggestions, version });
  } catch (error) {
    console.error('Search suggestions error:', error);
    res.status(500).json({ error: 'Failed to get search suggestions' });
  }
});

// User preferences routes
app.get('/api/preferences', requireAuth, (req, res) => {
  preferencesOps.getPreferences(req.user.id, (err, preferences) => {
    if (err) {
      return res.status(500).json({ error: 'Failed to get preferences' });
    }
    res.json({
      font_size: preferences?.font_size || 'medium',
      dark_mode: !!preferences?.dark_mode
    });
  });
});

app.put('/api/preferences', requireAuth, (req, res) => {
  const { font_size, dark_mode } = req.body;
  
  // Validate font_size
  if (font_size && !['small', 'medium', 'large'].includes(font_size)) {
    return res.status(400).json({ error: 'Invalid font_size' });
  }

  preferencesOps.updatePreferences(req.user.id, { font_size, dark_mode }, (err) => {
    if (err) {
      return res.status(500).json({ error: 'Failed to update preferences' });
    }
    res.json({ message: 'Preferences updated successfully' });
  });
});

// Favorites routes
app.get('/api/favorites', requireAuth, (req, res) => {
  favoritesOps.getFavorites(req.user.id, (err, favorites) => {
    if (err) {
      return res.status(500).json({ error: 'Failed to get favorites' });
    }
    res.json({ favorites });
  });
});

app.post('/api/favorites', requireAuth, (req, res) => {
  const { book, chapter, verse_start, verse_end, note, version } = req.body;

  // Book is required, but chapter is optional (for book-level favorites)
  if (!book) {
    return res.status(400).json({ error: 'Book is required' });
  }

  const favorite = {
    book,
    chapter: chapter || null,
    verse_start: verse_start || null,
    verse_end: verse_end || null,
    version: version || 'esv',
    note: note || null
  };

  favoritesOps.addFavorite(req.user.id, favorite, function(err) {
    if (err) {
      if (err.code === 'SQLITE_CONSTRAINT') {
        return res.status(409).json({ error: 'Favorite already exists' });
      }
      return res.status(500).json({ error: 'Failed to add favorite' });
    }
    res.json({ 
      message: 'Favorite added successfully',
      id: this.lastID
    });
  });
});

app.delete('/api/favorites/:id', requireAuth, (req, res) => {
  const favoriteId = req.params.id;
  
  favoritesOps.removeFavorite(req.user.id, favoriteId, (err) => {
    if (err) {
      return res.status(500).json({ error: 'Failed to remove favorite' });
    }
    res.json({ message: 'Favorite removed successfully' });
  });
});

app.get('/api/favorites/check', requireAuth, (req, res) => {
  const { book, chapter, verse_start, verse_end } = req.query;
  
  if (!book) {
    return res.status(400).json({ error: 'Book is required' });
  }

  favoritesOps.isFavorited(
    req.user.id, 
    book, 
    chapter || null, 
    verse_start || null, 
    verse_end || null,
    (err, isFavorited) => {
      if (err) {
        return res.status(500).json({ error: 'Failed to check favorite status' });
      }
      res.json({ isFavorited });
    }
  );
});

// Catch-all handler: send back React's index.html for client-side routing
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '../../frontend/build/index.html'));
});

// Error handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something went wrong!' });
});

// Start server
app.listen(PORT, () => {
  console.log(`The Bible API server running on port ${PORT}`);
  if (esvSearchEngine) {
    console.log(`ESV data directory: ${ESV_DATA_DIR}`);
  } else {
    console.log(`ESV data not available - mdbible not found`);
  }
  console.log(`NKJV data directory: ${NKJV_DATA_DIR}`);
});
