require('dotenv').config()
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
const moment = require('moment')
const crypto = require('crypto')
const { Sequelize } = require('sequelize')
const { sequelize } = require('../../../models/migration.js')
const response = require('../../helpers/responses')
const { sendOTP, generateOTP, sendForgotPassword, normalizePhone } = require('../../helpers/helpers')
const UserResource = require('../resources/user.resource')
const { sendMail } = require('../../config/mail.config')
const db = require('../../../models/migration.js')
const { password } = require('../../config/db.config.js')
const errorHandler = require('../../middlewares/errorHandler.js')
const { v4: uuidv4 } = require("uuid");
const User = db.User
const Branch = db.Branch
const UserOtp = db.UserOtp
const PasswordReset = db.PasswordReset
const { Op } = require('sequelize')
const { OAuth2Client } = require("google-auth-library");

const signIn = async (req, res) => { 

const client = new OAuth2Client("GOOGLE_CLIENT_ID");

  try {
    const { email, phone, password, token: tokenGoogle, login_via } = req.body;
    let user;


    if (email) {
      user = await User.findOne({ where: { email } });

      if (login_via == 'GOOGLE') {
        // Verify Google token
        const ticket = await client.verifyIdToken({
          idToken: tokenGoogle, // Changed from tokenGoogle to idToken
          audience: process.env.GOOGLE_CLIENT_ID,
        });

        const payload = ticket.getPayload();
        const googleEmail = payload.email;

        // Find or create user with Google credentials
        user = await User.findOne({ 
          where: { 
            email: googleEmail
          }
        });

        if (!user) {
          // Create new user if doesn't exist
          user = await User.create({
            email: googleEmail,
            name: payload.name,
            login_via: 'GOOGLE',
            token: tokenGoogle,
            google_id: payload.sub,
            avatar_url: payload.picture,
          });
        }else{
          // Update user's Google token
          user.google_id = payload.sub;
          user.avatar_url = payload.picture;
          user.token = tokenGoogle;
          await user.save();
        }
      }

    } else if (phone) {
      const normalizedPhone = normalizePhone(phone);
      user = await User.findOne({ where: { phone: normalizedPhone } });
    }

    if (login_via === 'GOOGLE') {
    } else {
      if (!user || !(await bcrypt.compare(password, user.password))) {
        return res.status(400).json({ error: "Email / Phone atau Password salah" });
      }
    }

    if (user.is_suspended) {
      return res.status(403).json({ error: "Akun Anda telah ditangguhkan" });
    }

    const now = new Date();

    // === Generate JWT mirip Supabase ===
    
    const token = jwt.sign(
      {
        name: user.name,
        id: user.id,
        email: user.email,
        phone: user.phone || "",
        role: user.role || "user",
    
      },
      process.env.JWT_SECRET_KEY
    );


    // Update last login
    user.last_login = now;
    user.is_first_login = false;
    await user.save();

    return res.json({
      access_token: token,
      token_type: "bearer",
      user: {
          id: user.id,
          name: user.name,
          email: user.email,
          role: user.role || "user",
          created_at: user.created_at.toISOString(),
      },
    });
  } catch (error) {
    errorHandler(error, req, res)
    return response.failed(res, 500, error.message)
  }
};




const sendOtp = async (req, res) => {
  try {
    const { email, phone, via } = req.body
    const otp = generateOTP(6)
    const hash = await bcrypt.hash(otp, 10)
    const data = via === 'WHATSAPP' ? email : phone
    const otpData = await UserOtp.create({ data, otp, token: hash, expire_in: 60, via })

    await sendOTP('OTP', otp, via, phone, email)

    return response.success(res, { otpData }, `OTP dikirim ${via}`)
  } catch (error) {
    return response.failed(res, 500, error.message)
  }
}

const checkOtp = async (req, res) => {
  try {
    const { otp, token } = req.body
    const data = await UserOtp.findOne({ where: { otp, token } })

    if (!data) {
      return response.failed(res, 404, 'OTP tidak valid')
    }

    const userCondition = data.via === 'WHATSAPP' ? { email: data.data } : { phone: data.data }
    let user = await User.findOne({ where: userCondition })

    if (!user) {
      user = await User.create(userCondition)
    }

    const jwtToken = jwt.sign({ id: user.id }, process.env.JWT_SECRET_KEY, { expiresIn: '1d' })
    return response.success(res, { user: new UserResource(user), token: jwtToken }, 'Login OTP berhasil')


  } catch (error) {
    return response.failed(res, 500, error.message)
  }
}

const signUp = async (req, res) => {
  try {
    const { name, email, password, role, branch_id  } = req.body;

   
    // Cek apakah email / phone sudah ada
    const existingUser = await User.findOne({
      where: {
        [Sequelize.Op.or]: [{ email }],
      },
    });

    if (existingUser) {
      return res.status(400).json({ error: "Email sudah terdaftar" });
    }

    const branch = await Branch.findOne({ where: { id: branch_id } });
    if (!branch) {
      return response.failed(res, 404, "Branch tidak ditemukan");
    }

    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Buat user baru dalam transaksi
    const user = await sequelize.transaction(async (t) => {
      const newUser = await User.create(
        {
          name,
          email,
          branch_id,
          password: hashedPassword,
          role: role || "user",
        },
        { transaction: t }
      );

      return newUser;
    });

    // Generate token JWT
   

    const token = jwt.sign(
      {
        name: user.name,
        id: user.id,
        email: user.email,
        phone: user.phone || "",
        role: user.role || "user",
    
      },
      process.env.JWT_SECRET_KEY
    );

    const refreshToken = uuidv4();
    const now = new Date();

    // Update last_login setelah register
    user.last_login = now;
    user.is_first_login = false;
    await user.save();

    return res.json({
      access_token: token,
      token_type: "bearer",
      user: {
          id: user.id,
          name: user.name,
          email: user.email,
          branch: branch.name,
          role: user.role || "user",
          created_at: user.created_at.toISOString(),
      },
    });
  } catch (error) {
   errorHandler(error, req, res)
   return response.failed(res, 500, error.message)
  }
};


const getUserLogin = async (token, res) => {
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET_KEY)

    const user = await User.findByPk(decoded.id, {
      attributes: { exclude: ['password'] }
    })

    if (!user) {
      return response.failed(res, 404, 'User Tidak Ditemukan')
    }

    return response.success(res, new UserResource(user), 'User ditemukan')
  } catch (error) {
    return response.failed(res, 401, 'Token Tidak Valid atau expired')
  }
}



const forgotPassword = async (body, res) => {
  const [user, resetPassword] = await Promise.all([
    User.findOne({
      where: {
        email: body.email,
      },
    }),
    PasswordReset.findOne({
      where: {
        email: body.email,
        is_used: false,
      },
    }),
  ]);

  if (!user) {
    return response.error(res, 1307, 400);
  }

  if (resetPassword) {
    resetPassword.token = crypto.randomBytes(20).toString('hex');
    resetPassword.expires_at = moment().add(15, 'minutes').toISOString();

    await resetPassword.save();

    await sequelize.transaction(async () => {
      await sendForgotPassword(body.email, resetPassword.token);
    });

    const tokenUpdated = {
      user,
      forgot_password: resetPassword,
    };

    return response.success(res, tokenUpdated, 'Token Updated');
  }

  const emailToken = crypto.randomBytes(20).toString('hex');
  const expiresAt = moment().add(15, 'minutes').toISOString();

  const dataPasswordReset = await PasswordReset.create({
    email: body.email,
    token: emailToken,
    expires_at: expiresAt,
  });

  const tokenCreated = {
    user,
    forgot_password: dataPasswordReset,
  };

  return response.success(res, tokenCreated, 'Token Created');
};


const resetPassword = async (body, token, res) => {
  try {
    const resetPassword = await PasswordReset.findOne({
      where: {
        is_used: false,
        token: token,
      },
    });
    console.log('resetPassword data:', resetPassword);

    if (!resetPassword) {
      return response.error(res, 1306, 400);
    }

    const now = moment();
    const expiresAt = moment(resetPassword.expires_at);
    if (now.isAfter(expiresAt)) {
      return response.error(res, 1306, 400);
    }

    const password = body.new_password;
    const confirm_password = body.confirm_password;

    if (password !== confirm_password) {
      return response.failed(res, 1105, 400);
    }

    const salt = await bcrypt.genSalt(10);
    const hash = await bcrypt.hash(password, salt);

    const user = await User.findOne({
      where: {
        email: resetPassword.email,
      },
    });
    user.password = hash;
    user.is_default = false;
    await user.save();

    resetPassword.is_used = true;
    await resetPassword.save();

    return response.success(res, null, 'Password reset successfully');
  } catch (error) {
    console.error('Reset password error:', error);
    return response.failed(res, 500, error.message || 'Something went wrong');
  }
};


module.exports = {
  signIn,
  sendOtp,
  checkOtp,
  signUp,
  getUserLogin,
  resetPassword,
  forgotPassword
}




