const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { executeQuery } = require('../config/database');
const { v4: uuidv4 } = require('uuid');
const admin = require('firebase-admin');

// Initialize Firebase Admin SDK if not already initialized
if (!admin.apps.length) {
  try {
    admin.initializeApp({
      credential: admin.credential.applicationDefault()
    });
  } catch (error) {
    console.log('Firebase Admin SDK not initialized:', error.message);
  }
}

class AuthService {
  // Generate OTP
  generateOTP() {
    return Math.floor(100000 + Math.random() * 900000).toString();
  }

  // Check if user exists in database
  async checkUserExists(phoneNumber) {
    try {
      console.log(`🔍 Checking if user exists with phone number: ${phoneNumber}`);
      
      // Check if user exists in database
      const userQuery = 'SELECT id, phone_number, username, permission_level, status, company_id FROM users WHERE phone_number = ?';
      const users = await executeQuery(userQuery, [phoneNumber]);
      
      console.log(`📊 Found ${users.length} users with phone number ${phoneNumber}`);
      
      return users.length > 0;
    } catch (error) {
      console.error('Check user exists error:', error);
      return false;
    }
  }

  // Send OTP with pre-configured admin accounts
  async sendOTP(phoneNumber) {
    try {
      console.log(`🔍 Looking for user with phone number: ${phoneNumber}`);
      
      // Check if user exists in database
      const userQuery = 'SELECT id, phone_number, username, permission_level, status, company_id FROM users WHERE phone_number = ?';
      const users = await executeQuery(userQuery, [phoneNumber]);
      
      console.log(`📊 Found ${users.length} users with phone number ${phoneNumber}`);
      
      if (users.length === 0) {
        console.log(`❌ No user found with phone number: ${phoneNumber}`);
        return {
          success: false,
          message: 'User not found. Please contact admin to create your account.'
        };
      }

      const user = users[0];
      console.log(`✅ Found user:`, user);
      
      if (user.status !== 'active') {
        console.log(`❌ User account is not active: ${user.status}`);
        return {
          success: false,
          message: 'Your account is inactive. Please contact admin.'
        };
      }

      // For pre-configured admin accounts, use fixed OTP
      let otp;
      if (['1234567890', '1234512345', '1234567899'].includes(phoneNumber)) {
        otp = '123456'; // Fixed OTP for seeded accounts
      } else {
        otp = this.generateOTP(); // Generate random OTP for other users
      }

      console.log(`🔐 Generated OTP: ${otp}`);

      // Store OTP in database
      // First delete any existing OTP for this phone number
      await executeQuery('DELETE FROM otps WHERE phone_number = ?', [phoneNumber]);
      
      // Then insert the new OTP - using MySQL's NOW() function for consistency
      const otpQuery = `
        INSERT INTO otps (phone_number, otp_code, expires_at, created_at) 
        VALUES (?, ?, DATE_ADD(NOW(), INTERVAL ? MINUTE), NOW())
      `;
      
      // Use the configured OTP expiry time from environment variables
      const otpExpiryMinutes = parseInt(process.env.OTP_EXPIRY_MINUTES) || 5;
      
      await executeQuery(otpQuery, [phoneNumber, otp, otpExpiryMinutes]);

      // In production, send actual SMS via Twilio (except for admin accounts)
      if (process.env.NODE_ENV === 'production' && !['1234567890', '1234512345', '1234567899'].includes(phoneNumber)) {
        await this.sendSMS(phoneNumber, `Your OTP is: ${otp}. Valid for ${otpExpiryMinutes} minutes.`);
      }

      // For development, log the OTP
      if (process.env.NODE_ENV !== 'production') {
        console.log(`OTP for ${phoneNumber}: ${otp}`);
      }

      return {
        success: true,
        message: 'OTP sent successfully',
        ...(process.env.NODE_ENV !== 'production' && { testOTP: otp }) // Include OTP in response for testing
      };

    } catch (error) {
      console.error('Send OTP error:', error);
      return {
        success: false,
        message: 'Failed to send OTP. Please try again.'
      };
    }
  }

  // Verify OTP
  async verifyOTP(phoneNumber, otpCode) {
    try {
      console.log(`🔍 Verifying OTP for phone number: ${phoneNumber}, code: ${otpCode}`);
      
      // Check for valid OTP in database
      const otpRecord = await executeQuery(
        `SELECT * FROM otps 
         WHERE phone_number = ? AND otp_code = ? 
         AND expires_at > NOW() 
         AND is_used = 0 
         ORDER BY created_at DESC LIMIT 1`,
        [phoneNumber, otpCode]
      );

      console.log(`📊 Found ${otpRecord.length} valid OTP records`);

      if (otpRecord.length === 0) {
        return {
          success: false,
          message: 'Invalid or expired OTP'
        };
      }

      // Mark OTP as used
      await executeQuery(
        'UPDATE otps SET is_used = 1 WHERE id = ?',
        [otpRecord[0].id]
      );

      return {
        success: true,
        message: 'OTP verified successfully'
      };
    } catch (error) {
      console.error('Error verifying OTP:', error);
      return {
        success: false,
        message: 'Failed to verify OTP'
      };
    }
  }

  // Firebase Login
  async firebaseLogin(firebaseToken, phoneNumber) {
    try {
      console.log(`🔍 Firebase login for phone number: ${phoneNumber}`);
      const isTestToken =
        process.env.NODE_ENV !== 'production' &&
        firebaseToken === 'test_firebase_token';

      let decodedToken = { uid: 'unknown' };

      if (isTestToken) {
        console.log('🧪 Skipping Firebase token verification for test token');
        decodedToken = { uid: `test-${phoneNumber}` };
      } else {
        if (!admin.apps.length) {
          throw new Error(
            'Firebase Admin SDK is not initialized. Please configure service credentials.',
          );
        }
        // Verify Firebase token
        decodedToken = await admin.auth().verifyIdToken(firebaseToken);
        console.log(`✅ Firebase token verified for user: ${decodedToken.uid}`);
      }
      
      // Get user with company information
      const userQuery = `
        SELECT u.*, c.name as company_name
        FROM users u
        LEFT JOIN companies c ON u.company_id = c.id
        WHERE u.phone_number = ? AND u.status = 'active'
      `;
      
      const users = await executeQuery(userQuery, [phoneNumber]);

      if (users.length === 0) {
        return {
          success: false,
          message: 'User not found or inactive. Please contact administrator.'
        };
      }

      const user = users[0];

      // Generate tokens
      const { accessToken, refreshToken } = this.generateTokens(user.id);

      // Store refresh token
      const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
      const formattedExpiresAt = expiresAt.toISOString().slice(0, 19).replace('T', ' ');
      await executeQuery(
        'INSERT INTO refresh_tokens (user_id, token, expires_at, created_at) VALUES (?, ?, ?, NOW())',
        [user.id, refreshToken, formattedExpiresAt]
      );

      // Get user permissions
      const permissionsQuery = `
        SELECT permission_name, permission_value
        FROM user_permissions
        WHERE user_id = ?
      `;
      const permissions = await executeQuery(permissionsQuery, [user.id]);

      // Get user's projects
      const projectsQuery = `
        SELECT p.id, p.name, p.description, pm.role as project_role
        FROM projects p
        JOIN project_members pm ON p.id = pm.project_id
        WHERE pm.user_id = ?
      `;
      const projects = await executeQuery(projectsQuery, [user.id]);

      return {
        success: true,
        message: 'Login successful',
        data: {
          user: {
            id: user.id,
            username: user.username,
            phone_number: user.phone_number,
            permission_level: user.permission_level,
            status: user.status,
            company_id: user.company_id,
            company_name: user.company_name,
            created_at: user.created_at,
            updated_at: user.updated_at
          },
          permissions: permissions,
          projects: projects,
          tokens: {
            access_token: accessToken,
            refresh_token: refreshToken
          }
        }
      };
    } catch (error) {
      console.error('Firebase login error:', error);
      return {
        success: false,
        message: 'Firebase login failed. Please try again.'
      };
    }
  }

  // Generate JWT tokens
  generateTokens(userId) {
    const accessToken = jwt.sign(
      { userId },
      process.env.JWT_SECRET,
      { expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
    );

    const refreshToken = jwt.sign(
      { userId, tokenId: uuidv4() },
      process.env.JWT_REFRESH_SECRET,
      { expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '30d' }
    );

    return { accessToken, refreshToken };
  }

  // Store refresh token
  async storeRefreshToken(userId, refreshToken) {
    try {
      const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
      const expiresAt = new Date(decoded.exp * 1000);

      await executeQuery(
        'INSERT INTO refresh_tokens (user_id, token, expires_at) VALUES (?, ?, ?)',
        [userId, refreshToken, expiresAt]
      );
    } catch (error) {
      console.error('Error storing refresh token:', error);
      throw new Error('Failed to store refresh token');
    }
  }

  // Login user
  async login(phoneNumber, otpCode) {
    try {
      // Verify OTP first
      const otpVerification = await this.verifyOTP(phoneNumber, otpCode);
      if (!otpVerification.success) {
        return otpVerification;
      }

      // Get user with company information
      const userQuery = `
        SELECT u.*, c.name as company_name
        FROM users u
        LEFT JOIN companies c ON u.company_id = c.id
        WHERE u.phone_number = ? AND u.status = 'active'
      `;
      
      const users = await executeQuery(userQuery, [phoneNumber]);

      if (users.length === 0) {
        return {
          success: false,
          message: 'User not found or inactive. Please contact administrator.'
        };
      }

      const user = users[0];

      // Generate tokens
      const { accessToken, refreshToken } = this.generateTokens(user.id);

      // Store refresh token
      const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
      const formattedExpiresAt = expiresAt.toISOString().slice(0, 19).replace('T', ' ');
      await executeQuery(
        'INSERT INTO refresh_tokens (user_id, token, expires_at, created_at) VALUES (?, ?, ?, NOW())',
        [user.id, refreshToken, formattedExpiresAt]
      );

      // Get user permissions
      const permissionsQuery = `
        SELECT permission_name, permission_value
        FROM user_permissions
        WHERE user_id = ?
      `;
      const permissions = await executeQuery(permissionsQuery, [user.id]);

      // Get user's projects
      const projectsQuery = `
        SELECT p.id, p.name, p.description, pm.role as project_role
        FROM projects p
        JOIN project_members pm ON p.id = pm.project_id
        WHERE pm.user_id = ?
      `;
      const projects = await executeQuery(projectsQuery, [user.id]);

      return {
        success: true,
        message: 'Login successful',
        data: {
          user: {
            id: user.id,
            username: user.username,
            phone_number: user.phone_number,
            permission_level: user.permission_level,
            status: user.status,
            company_id: user.company_id,
            company_name: user.company_name,
            created_at: user.created_at,
            updated_at: user.updated_at
          },
          permissions: permissions,
          projects: projects,
          tokens: {
            access_token: accessToken,
            refresh_token: refreshToken
          }
        }
      };
    } catch (error) {
      console.error('Login error:', error);
      return {
        success: false,
        message: 'Login failed. Please try again.'
      };
    }
  }

  // Refresh access token
  async refreshToken(refreshToken) {
    try {
      const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);

      // Check if refresh token exists and is valid
      const tokenRecord = await executeQuery(
        `SELECT * FROM refresh_tokens 
         WHERE user_id = ? AND token = ? 
         AND expires_at > NOW()`,
        [decoded.userId, refreshToken]
      );

      if (tokenRecord.length === 0) {
        return {
          success: false,
          message: 'Invalid or expired refresh token'
        };
      }

      // Generate new access token
      const newAccessToken = jwt.sign(
        { userId: decoded.userId },
        process.env.JWT_SECRET,
        { expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
      );

      return {
        success: true,
        message: 'Token refreshed successfully',
        data: {
          access_token: newAccessToken
        }
      };
    } catch (error) {
      console.error('Token refresh error:', error);
      return {
        success: false,
        message: 'Invalid refresh token'
      };
    }
  }

  // Logout user
  async logout(refreshToken) {
    try {
      await executeQuery(
        'DELETE FROM refresh_tokens WHERE token = ?',
        [refreshToken]
      );

      return {
        success: true,
        message: 'Logged out successfully'
      };
    } catch (error) {
      console.error('Logout error:', error);
      return {
        success: false,
        message: 'Failed to logout'
      };
    }
  }

  // Logout from all devices
  async logoutAll(userId) {
    try {
      await executeQuery(
        'DELETE FROM refresh_tokens WHERE user_id = ?',
        [userId]
      );

      return {
        success: true,
        message: 'Logged out from all devices successfully'
      };
    } catch (error) {
      console.error('Logout all error:', error);
      return {
        success: false,
        message: 'Failed to logout from all devices'
      };
    }
  }

  // Send SMS (placeholder for Twilio integration)
  async sendSMS(phoneNumber, message) {
    // In production, integrate with Twilio or other SMS service
    console.log(`📱 SMS to ${phoneNumber}: ${message}`);
    return { success: true, message: 'SMS sent successfully' };
  }
}

module.exports = new AuthService();
