const passport = require('passport');
const { Users, UsersPrivacyFlags, UsersFlags, LoginSessions } = require('../models');
const { Op } = require('sequelize');
const { getBrowserInfo } = require('../helpers/get-browser-info');
const LocalStrategy = require('passport-local').Strategy;
const axios = require('axios');

passport.use(
	'signup',
	new LocalStrategy(
		{ usernameField: 'emailAddress', passReqToCallback: true },
		async (req, emailAddress, password, done) => {
			try {
				const {
					phoneNo,
					firstname,
					lastname,
					birthdate,
					addressCountry,
					addressCity,
					addressStreet,
					addressZip,
					addressApt,
					addressState,
					language,
				} = req.body;

				const existingUser = await Users.findOne({
					where: {
						[Op.or]: [{ phone_no: phoneNo }, { email_address: emailAddress }],
					},
				});

				if (existingUser) {
					const message =
						existingUser.phone_no === phoneNo ? 'Phone number is already in use.' : 'Email address is already in use.';
					return done(null, false, { message });
				}

				const newUser = await Users.create({
					email_address: emailAddress,
					password: password,
					firstname: firstname,
					lastname: lastname,
					phone_no: phoneNo,
					birthdate: birthdate,
					address_country: addressCountry,
					address_city: addressCity,
					address_street: addressStreet,
					address_zip: addressZip,
					address_apt: addressApt,
					address_state: addressState,
					language,
				});

				await UsersPrivacyFlags.create({
					user_id: newUser.id,
					read_receipts: req.body.readReceipts,
					view_my_on_listings: req.body?.viewMyOnListings,
					display_my_location: req.body?.displayMyLocation,
					display_trip_details: req.body?.displayTripDetails,
					display_duration_of_visit: req.body?.displayDurationOfVisit,
				});

				await UsersFlags.create({
					user_id: newUser.id,
					travel_advice: req.body.travelAdvice,
					travel_advice_email: req.body.travelAdviceEmail,
					travel_advice_message: req.body.travelAdviceMessage,
					account_management_and_guidelines: req.body.accountManagementAndGuidelines,
					account_management_and_guidelines_email: req.body.accountManagementAndGuidelinesEmail,
					account_management_and_guidelines_message: req.body.accountManagementAndGuidelinesMessage,
					travelers_and_host_messages: req.body.travelersAndHostMessages,
					travelers_and_host_messages_email: req.body.travelersAndHostMessagesEmail,
					travelers_and_host_messages_message: req.body.travelersAndHostMessagesMessage,
				});

				return done(null, newUser);
			} catch (error) {
				return done(error);
			}
		},
	),
);

passport.use(
	'login',
	new LocalStrategy(
		{ usernameField: 'emailOrPhone', passwordField: 'password', passReqToCallback: true },
		async (req, emailOrPhone, password, done) => {
			try {
				const user = await Users.findOne({
					where: {
						[Op.and]: [
							{
								[Op.or]: [{ email_address: emailOrPhone }, { phone_no: emailOrPhone }],
							},
						],
					},
				});

				if (!user || !(await user.validatePassword(password))) {
					return done(null, false, { message: 'Invalid email/phone or password' });
				}

				if (user.status === false) {
					user.status = true;
					await user.save();
				}

				const ip = req.ip || req.headers['x-forwarded-for'] || 'Unknown';

				// fetch geolocation data based on the IP address using ipinfo.io API
				let address = null;
				let lat = null;
				let lng = null;

				if (ip !== 'Unknown') {
					try {
						const response = await axios.get(`https://ipinfo.io/${ip}/json?token=${process.env.IP_API_KEY}`);
						const location = response.data;

						address = location.city || location.region || location.country || 'Unknown';
						const [latitude, longitude] = location.loc ? location.loc.split(',') : [null, null];
						lat = latitude;
						lng = longitude;
					} catch (geoError) {
						console.error('Geolocation fetch error:', geoError);
					}
				}

				const browserInfo = getBrowserInfo(req);

				await LoginSessions.create({
					user_id: user.id,
					ip_address: ip,
					browser: `${browserInfo.browser} ${browserInfo.version}`,
					os: browserInfo.platform,
					device: browserInfo.device,
					address: address,
					lng: lng,
					lat: lat,
				});

				return done(null, user);
			} catch (error) {
				return done(error);
			}
		},
	),
);

passport.serializeUser((user, done) => {
	done(null, user.id);
});

passport.deserializeUser(async (id, done) => {
	try {
		const user = await Users.findByPk(id);
		done(null, user);
	} catch (error) {
		done(error);
	}
});

module.exports = passport;
