const sqlite3 = require("sqlite3").verbose();
const path = require("path");

class DatabaseService {
  constructor() {
    this.dbPath = path.join(__dirname, "..", "database", "travel_rates.db");
    this.db = null;
  }

  connect() {
    return new Promise((resolve, reject) => {
      this.db = new sqlite3.Database(this.dbPath, (err) => {
        if (err) {
          console.error("❌ Database connection failed:", err);
          reject(err);
        } else {
          console.log("✅ Database connected");
          resolve();
        }
      });
    });
  }

  /**
   * Search for a city (complete travel rates)
   * GUARANTEED to find Canberra!
   */
  async searchCity(searchTerm) {
    const query = `
            SELECT * FROM travel_rates
            WHERE LOWER(city_name) LIKE LOWER(?) 
            OR LOWER(city_key) LIKE LOWER(?)
            OR LOWER(country) LIKE LOWER(?)
            OR LOWER(province) LIKE LOWER(?)
            ORDER BY 
                CASE 
                    WHEN LOWER(city_name) = LOWER(?) THEN 1
                    WHEN LOWER(city_key) = LOWER(?) THEN 2
                    WHEN LOWER(city_name) LIKE LOWER(?) THEN 3
                    ELSE 4
                END
            LIMIT 10
        `;

    const term = `%${searchTerm}%`;
    const exactTerm = searchTerm.toLowerCase();
    const likeTerm = `${searchTerm.toLowerCase()}%`;

    return new Promise((resolve, reject) => {
      this.db.all(
        query,
        [term, term, term, term, exactTerm, exactTerm, likeTerm],
        (err, rows) => {
          if (err) reject(err);
          else
            resolve(rows ? rows.map((row) => this.formatTravelRate(row)) : []);
        }
      );
    });
  }

  /**
   * Get complete travel rate by exact city key
   */
  async getAccommodationRate(cityKey) {
    const query = `SELECT * FROM travel_rates WHERE LOWER(city_key) = LOWER(?) LIMIT 1`;

    return new Promise((resolve, reject) => {
      this.db.get(query, [cityKey], (err, row) => {
        if (err) reject(err);
        else resolve(row ? this.formatTravelRate(row) : null);
      });
    });
  }

  /**
   * Get accommodation rate for a specific month
   */
  async getMonthlyRate(cityKey, month) {
    const rate = await this.getAccommodationRate(cityKey);

    if (!rate) return null;

    const monthIndex = month - 1; // 0-based index
    return {
      city: rate.name,
      month: month,
      rate: rate.monthlyRates[monthIndex],
      currency: rate.currency,
    };
  }

  /**
   * Full-text search across all cities
   */
  async fullTextSearch(searchTerm) {
    const query = `
            SELECT a.* FROM travel_rates a
            WHERE a.id IN (
                SELECT rowid FROM travel_search 
                WHERE travel_search MATCH ?
            )
            ORDER BY 
                CASE 
                    WHEN LOWER(a.city_name) = LOWER(?) THEN 1
                    ELSE 2
                END
            LIMIT 20
        `;

    return new Promise((resolve, reject) => {
      this.db.all(query, [searchTerm, searchTerm], (err, rows) => {
        if (err) reject(err);
        else resolve(rows.map((row) => this.formatTravelRate(row)));
      });
    });
  }

  /**
   * Format complete travel rate for API response
   */
  formatTravelRate(row) {
    return {
      cityKey: row.city_key,
      name: row.city_name,
      province: row.province,
      country: row.country,
      region: row.region,
      currency: row.currency,
      accommodation: {
        monthly: [
          row.jan_accommodation,
          row.feb_accommodation,
          row.mar_accommodation,
          row.apr_accommodation,
          row.may_accommodation,
          row.jun_accommodation,
          row.jul_accommodation,
          row.aug_accommodation,
          row.sep_accommodation,
          row.oct_accommodation,
          row.nov_accommodation,
          row.dec_accommodation,
        ],
        standard: row.standard_accommodation,
      },
      meals: {
        breakfast: row.breakfast,
        lunch: row.lunch,
        dinner: row.dinner,
        total: row.total_meals,
      },
      incidentals: row.incidentals,
      totalDailyAllowance: row.total_daily_allowance,
      fullDayCost:
        parseFloat(row.standard_accommodation || row.jan_accommodation) +
        parseFloat(row.total_daily_allowance),
      isInternational: row.is_international === 1,
    };
  }

  /**
   * Legacy format for backward compatibility
   */
  formatAccommodationRate(row) {
    return {
      cityKey: row.city_key,
      name: row.city_name,
      province: row.province,
      country: row.country,
      region: row.region,
      currency: row.currency,
      monthlyRates: [
        row.jan_accommodation || row.jan_rate,
        row.feb_accommodation || row.feb_rate,
        row.mar_accommodation || row.mar_rate,
        row.apr_accommodation || row.apr_rate,
        row.may_accommodation || row.may_rate,
        row.jun_accommodation || row.jun_rate,
        row.jul_accommodation || row.jul_rate,
        row.aug_accommodation || row.aug_rate,
        row.sep_accommodation || row.sep_rate,
        row.oct_accommodation || row.oct_rate,
        row.nov_accommodation || row.nov_rate,
        row.dec_accommodation || row.dec_rate,
      ],
      standardRate: row.standard_accommodation || row.standard_rate,
      isInternational: row.is_international === 1,
      effectiveDate: row.effective_date,
    };
  }

  /**
   * List all cities by region
   */
  async getCitiesByRegion(region) {
    const query = `
            SELECT * FROM travel_rates 
            WHERE region = ? 
            ORDER BY city_name
        `;

    return new Promise((resolve, reject) => {
      this.db.all(query, [region], (err, rows) => {
        if (err) reject(err);
        else resolve(rows.map((row) => this.formatAccommodationRate(row)));
      });
    });
  }

  /**
   * List all cities by country
   */
  async getCitiesByCountry(country) {
    const query = `
            SELECT * FROM travel_rates 
            WHERE LOWER(country) = LOWER(?) 
            ORDER BY city_name
        `;

    return new Promise((resolve, reject) => {
      this.db.all(query, [country], (err, rows) => {
        if (err) reject(err);
        else resolve(rows.map((row) => this.formatAccommodationRate(row)));
      });
    });
  }

  /**
   * Get all available regions
   */
  async getAllRegions() {
    const query = `SELECT DISTINCT region FROM travel_rates ORDER BY region`;

    return new Promise((resolve, reject) => {
      this.db.all(query, [], (err, rows) => {
        if (err) reject(err);
        else resolve(rows.map((row) => row.region));
      });
    });
  }

  /**
   * Get all available countries
   */
  async getAllCountries() {
    const query = `SELECT DISTINCT country FROM travel_rates ORDER BY country`;

    return new Promise((resolve, reject) => {
      this.db.all(query, [], (err, rows) => {
        if (err) reject(err);
        else resolve(rows.map((row) => row.country));
      });
    });
  }

  /**
   * Autocomplete for city search
   */
  async autocomplete(prefix, limit = 10) {
    const query = `
            SELECT city_name, country, region FROM travel_rates
            WHERE LOWER(city_name) LIKE LOWER(?)
            ORDER BY 
                CASE 
                    WHEN LOWER(city_name) LIKE LOWER(?) THEN 1
                    ELSE 2
                END,
                city_name
            LIMIT ?
        `;

    const term = `${prefix}%`;
    const exactTerm = `${prefix}`;

    return new Promise((resolve, reject) => {
      this.db.all(query, [term, exactTerm, limit], (err, rows) => {
        if (err) reject(err);
        else resolve(rows);
      });
    });
  }

  /**
   * Get all per-diem rates
   */
  async getAllPerDiemRates() {
    const query = `
            SELECT country, city_name as city, breakfast, lunch, dinner, 
                   incidentals, currency
            FROM travel_rates
            WHERE country IS NOT NULL 
            AND country != 'Canada'
            ORDER BY country, city_name
        `;

    return new Promise((resolve, reject) => {
      this.db.all(query, [], (err, rows) => {
        if (err) reject(err);
        else resolve(rows);
      });
    });
  }

  /**
   * Get all accommodation rates
   */
  async getAllAccommodations() {
    const query = `
            SELECT city_name as city, province, accommodation_rate as rate, currency
            FROM travel_rates
            WHERE country = 'Canada'
            AND accommodation_rate IS NOT NULL
            ORDER BY province, city_name
        `;

    return new Promise((resolve, reject) => {
      this.db.all(query, [], (err, rows) => {
        if (err) reject(err);
        else resolve(rows);
      });
    });
  }

  /**
   * Get statistics
   */
  async getStats() {
    const queries = {
      countries: `SELECT COUNT(DISTINCT country) as count FROM travel_rates WHERE country != 'Canada'`,
      accommodations: `SELECT COUNT(*) as count FROM travel_rates WHERE country = 'Canada' AND accommodation_rate IS NOT NULL`,
      perDiem: `SELECT COUNT(*) as count FROM travel_rates WHERE country != 'Canada'`,
    };

    const results = {};
    for (const [key, query] of Object.entries(queries)) {
      results[key] = await new Promise((resolve, reject) => {
        this.db.get(query, [], (err, row) => {
          if (err) reject(err);
          else resolve(row.count);
        });
      });
    }
    return results;
  }

  close() {
    if (this.db) {
      this.db.close();
      console.log("✅ Database connection closed");
    }
  }
}

module.exports = new DatabaseService();
