const axios = require('axios');
const config = require('../config');
const db = require('../db/models');
const { v4: uuidv4 } = require('uuid');
const fs = require('fs');
const path = require('path');

class GooglePlacesService {
  constructor() {
    this.apiKey = config.google.placesApiKey;
    this.baseUrl = 'https://maps.googleapis.com/maps/api/place';
  }

  async searchPlaces(query, location) {
    if (!this.apiKey) {
      console.warn('Google Places API key is missing');
      return [];
    }

    try {
      const params = {
        query,
        key: this.apiKey,
      };
      if (location) {
        params.location = location;
      }


      const response = await axios.get(`${this.baseUrl}/textsearch/json`, { params });


      return response.data.results || [];
    } catch (error) {
      console.error('Error searching Google Places:', error.message);
      return [];
    }
  }

  async getPlaceDetails(placeId) {
    if (!this.apiKey) return null;

    try {
      const response = await axios.get(`${this.baseUrl}/details/json`, {
        params: {
          place_id: placeId,
          fields: 'name,formatted_address,address_components,formatted_phone_number,website,opening_hours,geometry,rating,types,photos,editorial_summary',
          key: this.apiKey,
        },
      });

      return response.data.result;
    } catch (error) {
      console.error('Error getting Google Place details:', error.message);
      return null;
    }
  }

  async importFromGoogle(googlePlace) {
    const transaction = await db.sequelize.transaction();
    try {
      // Check if business already exists by google_place_id
      let business = await db.businesses.findOne({
        where: { google_place_id: googlePlace.place_id },
        transaction,
      });

      if (business) {
        // Even if it exists, we might want to update the description or hours if missing
        if (!business.description || !business.hours_json) {
           const details = await this.getPlaceDetails(googlePlace.place_id);
           if (details) {
             let updated = false;
             if (!business.description && details.editorial_summary) {
               business.description = details.editorial_summary.overview;
               updated = true;
             }
             if (!business.hours_json && details.opening_hours) {
               business.hours_json = JSON.stringify(details.opening_hours);
               updated = true;
             }
             if (updated) {
               await business.save({ transaction });
             }
           }
        }
        await transaction.commit();
        return business;
      }

      // If it's a new business, let's fetch full details to get the description
      const details = await this.getPlaceDetails(googlePlace.place_id);
      const placeData = details || googlePlace;

      // Try to parse city/state/zip from address if available
      let city = null;
      let state = null;
      let zip = null;

      const formattedAddress = placeData.formatted_address || googlePlace.formatted_address || googlePlace.vicinity;
      if (formattedAddress) {
        const parts = formattedAddress.split(',');
        if (parts.length >= 3) {
           // Typically "City, State Zip, Country" or "City, State, Country"
           city = parts[parts.length - 3].trim();
           const stateZip = parts[parts.length - 2].trim().split(' ');
           if (stateZip.length >= 1) state = stateZip[0];
           if (stateZip.length >= 2) zip = stateZip[1];
        }
      }

      // Prepare business data
      const businessData = {
        id: uuidv4(),
        name: placeData.name,
        slug: placeData.name.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
        address: formattedAddress,
        city,
        state,
        zip,
        lat: placeData.geometry?.location?.lat,
        lng: placeData.geometry?.location?.lng,
        google_place_id: googlePlace.place_id,
        rating: placeData.rating || 0,
        is_active: true,
        is_claimed: false,
        hours_json: placeData.opening_hours ? JSON.stringify(placeData.opening_hours) : null,
        description: placeData.editorial_summary?.overview || null,
        phone: placeData.formatted_phone_number || null,
        website: placeData.website || null,
      };

      business = await db.businesses.create(businessData, { transaction });

      // Handle categories/types
      const types = placeData.types || googlePlace.types;
      if (types) {
        for (const type of types) {
          // Find or create category
          let category = await db.categories.findOne({
            where: { name: { [db.Sequelize.Op.iLike]: type.replace(/_/g, ' ') } },
            transaction,
          });

          if (!category) {
            // Include beauty types AND common service types found on landing page
            const allowedTypes = [
              'beauty_salon', 'hair_care', 'spa', 'health', 'cosmetics', 'beauty_product', 'hair_salon', 'massage', 'nail_salon', 'skin_care',
              'plumber', 'electrician', 'hvac_contractor', 'painter', 'home_improvement_contractor', 'general_contractor', 'cleaning_service', 'locksmith', 'roofing_contractor'
            ];
            if (allowedTypes.includes(type)) {
              category = await db.categories.create({
                id: uuidv4(),
                name: type.replace(/_/g, ' ').charAt(0).toUpperCase() + type.replace(/_/g, ' ').slice(1),
                slug: type.replace(/_/g, '-'),
                is_active: true,
              }, { transaction });
            }
          }

          if (category) {
            await db.business_categories.create({
              id: uuidv4(),
              businessId: business.id,
              categoryId: category.id,
            }, { transaction });
          }
        }
      }

      // Handle photos
      const photos = placeData.photos || googlePlace.photos;
      if (photos && photos.length > 0) {
        const photo = photos[0];
        const photoReference = photo.photo_reference;
        const photoUrl = `${this.baseUrl}/photo?maxwidth=800&photoreference=${photoReference}&key=${this.apiKey}`;
        
        try {
          const imageResponse = await axios({
            method: 'get',
            url: photoUrl,
            responseType: 'arraybuffer'
          });

          const filename = `${uuidv4()}.jpg`;
          const filePath = path.join(config.uploadDir, 'business_photos', 'photos', filename);
          
          // Ensure directory exists
          const dir = path.dirname(filePath);
          if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
          }

          fs.writeFileSync(filePath, imageResponse.data);

          const businessPhoto = await db.business_photos.create({
            id: uuidv4(),
            businessId: business.id,
          }, { transaction });

          await db.file.create({
            id: uuidv4(),
            name: filename,
            sizeInBytes: imageResponse.data.length,
            publicUrl: `business_photos/photos/${filename}`,
            privateUrl: `business_photos/photos/${filename}`,
            belongsTo: db.business_photos.getTableName(),
            belongsToId: businessPhoto.id,
            belongsToColumn: 'photos',
          }, { transaction });

        } catch (photoError) {
          console.error('Error importing photo from Google:', photoError.message);
        }
      }

      await transaction.commit();
      return business;
    } catch (error) {
      await transaction.rollback();
      console.error('Error importing from Google:', error);
      throw error;
    }
  }
}

module.exports = new GooglePlacesService();