const UnitOfWork = require('../../database/UnitOfWork');
const PersonalProfileService = require('../../services/profile/personal/PersonalProfileService');
const PersonalUserRepository = require('../../repositories/user/personal/PersonalUserRepository');
const { logger } = require('../../middleware/logger');

// helpers
const MAX = {
  name: 100,
  email: 255,
  phone: 32,
  address: 255,
  accountHolder: 140,
  iban: 34
};
const trim = v => (typeof v === 'string' ? v.trim() : v);
const isEmail = v => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
const isPhone = v => v ? /^\+?[1-9]\d{6,14}$/.test(v) : true;
const normalizeIban = v => (v || '').replace(/[^a-zA-Z0-9]/g, '').toUpperCase(); // sanitize only, no validation
const truncate = (s, n) => (typeof s === 'string' && s.length > n ? s.slice(0, n) : s);
const maskIban = v => {
  const s = normalizeIban(v || '');
  if (!s) return null;
  const last4 = s.slice(-4);
  return `**** **** **** **** **** **** **** ${last4}`.replace(/\s{2,}/g, ' ');
};

class PersonalProfileController {
  static async completeProfile(req, res) {
    const userId = req.user.userId;
    const profileData = req.body;
    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    logger.info('PersonalProfileController:completeProfile:start', { userId, profileData });
    try {
      const repo = new PersonalUserRepository(unitOfWork);
      await repo.updateProfileAndMarkCompleted(userId, profileData); // Correct method name
      await unitOfWork.commit();
      logger.info('PersonalProfileController:completeProfile:success', { userId });
      res.json({ success: true, message: 'Personal profile completed successfully' });
    } catch (error) {
      await unitOfWork.rollback(error);
      logger.error('PersonalProfileController:completeProfile:error', { userId, error });
      res.status(400).json({ success: false, message: error.message });
    }
  }

  static async updateBasic(req, res) {
    if (!req.user) return res.status(401).json({ success: false, message: 'Unauthenticated' });
    res.setHeader('X-Controller', 'PersonalProfileController:updateBasic'); // prove controller is hit

    // prefer camelCase, then snake_case, then infer from route namespace
    const inferredFromRoute = req.baseUrl?.includes('/profile/personal') || req.originalUrl?.includes('/profile/personal') ? 'personal' : undefined;
    const userType = req.user.userType ?? req.user.user_type ?? inferredFromRoute;

    const authDebugBasic = {
      derivedUserType: userType,
      reqUserKeys: Object.keys(req.user || {}),
      id: req.user?.id,
      userId: req.user?.userId
    };
    logger.info(`PersonalProfileController:updateBasic:auth userType=${userType} keys=${authDebugBasic.reqUserKeys.join(',')}`);
    console.log('[PersonalProfileController:updateBasic] auth', authDebugBasic);

    if (userType !== 'personal') {
      const message = 'Personal user required';
      const debug = process.env.NODE_ENV !== 'production'
        ? { expected: 'personal', got: userType, reqUserKeys: authDebugBasic.reqUserKeys }
        : undefined;
      return res.status(400).json({ success: false, message, ...(debug && { debug }) });
    }

    const userId = req.user.id || req.user.userId;

    // Only take fields that are provided and non-empty after trim
    let { firstName, lastName, email, phone, address } = req.body || {};
    const updates = {};

    if (firstName !== undefined) {
      const v = truncate(trim(firstName), MAX.name);
      if (v !== '') updates.firstName = v;
    }
    if (lastName !== undefined) {
      const v = truncate(trim(lastName), MAX.name);
      if (v !== '') updates.lastName = v;
    }
    if (email !== undefined) {
      const v = truncate(trim(email), MAX.email);
      if (v !== '') updates.email = v;
    }
    if (phone !== undefined) {
      const v = truncate(trim(phone), MAX.phone);
      if (v !== '') updates.phone = v;
    }
    if (address !== undefined) {
      const v = truncate(trim(address), MAX.address);
      if (v !== '') updates.address = v;
    }

    // Validate only provided non-empty fields
    if (updates.email && !isEmail(updates.email)) {
      return res.status(400).json({ success: false, message: 'Invalid email' });
    }
    if (updates.phone && !isPhone(updates.phone)) {
      return res.status(400).json({ success: false, message: 'Invalid phone' });
    }

    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    logger.info('PersonalProfileController:updateBasic:start', { userId });

    try {
      const updated = await PersonalProfileService.updateBasic(userId, updates, unitOfWork);
      await unitOfWork.commit();

      if (!updated) return res.status(404).json({ success: false, message: 'User not found' });

      const response = { ...updated, iban: maskIban(updated.iban) };
      logger.info('PersonalProfileController:updateBasic:success', { userId });
      return res.status(200).json({ success: true, profile: response });
    } catch (err) {
      await unitOfWork.rollback(err);

      // add explicit debug for missing user_id column
      if (err?.message?.includes("Unknown column 'user_id'")) {
        logger.error('PersonalProfileController:updateBasic:schemaMismatch', {
          userId,
          error: err.message,
          sql: err.sql,
          sqlState: err.sqlState,
          code: err.code
        });
        res.setHeader('X-Error-Code', 'SCHEMA_MISMATCH_USER_ID');
        return res.status(500).json({
          success: false,
          message: 'Database schema mismatch: column user_id is missing.',
          debug: process.env.NODE_ENV !== 'production' ? {
            hint: 'Update the table to include user_id or change the repository SQL to use the correct column name.',
            repoFile: 'repositories/user/personal/PersonalUserRepository.js',
            repoLine: 302
          } : undefined
        });
      }

      logger.error('PersonalProfileController:updateBasic:error', { userId, error: err.message });
      if (err.code === 'EMAIL_CONFLICT') {
        return res.status(409).json({ success: false, message: 'Email already in use' });
      }
      return res.status(400).json({ success: false, message: err.message || 'Invalid input' });
    }
  }

  static async updateBank(req, res) {
    if (!req.user) return res.status(401).json({ success: false, message: 'Unauthenticated' });
    res.setHeader('X-Controller', 'PersonalProfileController:updateBank'); // prove controller is hit

    // prefer camelCase, then snake_case, then infer from route namespace
    const inferredFromRoute = req.baseUrl?.includes('/profile/personal') || req.originalUrl?.includes('/profile/personal') ? 'personal' : undefined;
    const userType = req.user.userType ?? req.user.user_type ?? inferredFromRoute;

    const authDebugBank = {
      derivedUserType: userType,
      reqUserKeys: Object.keys(req.user || {}),
      id: req.user?.id,
      userId: req.user?.userId
    };
    logger.info(`PersonalProfileController:updateBank:auth userType=${userType} keys=${authDebugBank.reqUserKeys.join(',')}`);
    console.log('[PersonalProfileController:updateBank] auth', authDebugBank);

    if (userType !== 'personal') {
      const message = 'Personal user required';
      const debug = process.env.NODE_ENV !== 'production'
        ? { expected: 'personal', got: userType, reqUserKeys: authDebugBank.reqUserKeys }
        : undefined;
      return res.status(400).json({ success: false, message, ...(debug && { debug }) });
    }

    const userId = req.user.id || req.user.userId;

    let { accountHolder, iban } = req.body || {};
    const payload = {};

    // IBAN debug (pre-sanitize)
    const rawIban = iban ?? '';
    const normalizedIban = truncate(normalizeIban(rawIban), MAX.iban);

    // Log what we received vs what we will use
    const ibanDebug = {
      provided: iban !== undefined,
      raw: rawIban,
      rawLength: String(rawIban).length,
      normalized: normalizedIban,
      normalizedMasked: maskIban(normalizedIban),
      normalizedLength: normalizedIban.length,
      truncatedTo: MAX.iban
    };
    logger.info('PersonalProfileController:updateBank:iban_debug', { userId, ...ibanDebug });
    console.log('[PersonalProfileController:updateBank] iban_debug', ibanDebug);
    // Small headers for quick check in browser Network panel (avoid large payload)
    res.setHeader('X-IBAN-Len', String(ibanDebug.normalizedLength));
    if (ibanDebug.normalizedMasked) res.setHeader('X-IBAN-Masked', ibanDebug.normalizedMasked);

    if (accountHolder !== undefined) {
      const v = truncate(trim(accountHolder), MAX.accountHolder);
      if (v !== '') payload.accountHolderName = v;
    }
    if (iban !== undefined) {
      // sanitize only; do not validate IBAN format
      if (normalizedIban !== '') {
        payload.iban = normalizedIban;
      }
    }

    // Log final payload forwarded to service (mask IBAN)
    const payloadLog = {
      ...payload,
      ...(payload.iban ? { iban: maskIban(payload.iban) } : {})
    };
    logger.info('PersonalProfileController:updateBank:payload', { userId, payload: payloadLog });
    console.log('[PersonalProfileController:updateBank] payload', payloadLog);

    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    logger.info('PersonalProfileController:updateBank:start', { userId });

    try {
      const updated = await PersonalProfileService.updateBank(userId, payload, unitOfWork);
      await unitOfWork.commit();

      if (!updated) return res.status(404).json({ success: false, message: 'User not found' });

      const response = { ...updated, iban: maskIban(updated.iban) };
      logger.info('PersonalProfileController:updateBank:success', { userId, responsePreview: { iban: response.iban, accountHolderName: response.accountHolderName } });
      return res.status(200).json({ success: true, profile: response });
    } catch (err) {
      await unitOfWork.rollback(err);
      logger.error('PersonalProfileController:updateBank:error', { userId, error: err.message });
      res.setHeader('X-IBAN-Error', 'controller_catch');
      return res.status(400).json({ success: false, message: err.message || 'Invalid input' });
    }
  }
}

module.exports = PersonalProfileController;
