const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { User, Company, CompanyUser } = require('../models');
const { Op } = require('sequelize');

const generateToken = (user) =>
  jwt.sign({ id: user.id, email: user.email }, process.env.JWT_SECRET, {
    expiresIn: process.env.JWT_EXPIRES_IN || '7d',
  });

// POST /api/v1/auth/register
exports.register = async (req, res, next) => {
  try {
    const { name, email, password, company_name } = req.body;
    if (!name || !email || !password) {
      return res.status(400).json({ success: false, message: 'Name, email and password required' });
    }
    const existing = await User.findOne({ where: { email } });
    if (existing) return res.status(409).json({ success: false, message: 'Email already in use' });

    const password_hash = await bcrypt.hash(password, 12);
    const user = await User.create({ name, email, password_hash });

    // Create first company if provided
    if (company_name) {
      const company = await Company.create({ name: company_name });
      await CompanyUser.create({ company_id: company.id, user_id: user.id, role: 'owner' });
      // Setup default chart of accounts, sequences, etc.
      await setupCompanyDefaults(company.id);
    }

    const token = generateToken(user);
    res.status(201).json({
      success: true,
      data: { token, user: { id: user.id, name: user.name, email: user.email } },
    });
  } catch (err) { next(err); }
};

// POST /api/v1/auth/login
exports.login = async (req, res, next) => {
  try {
    const { email, password } = req.body;
    if (!email || !password) {
      return res.status(400).json({ success: false, message: 'Email and password required' });
    }
    const user = await User.findOne({ where: { email } });
    if (!user || !user.is_active) {
      return res.status(401).json({ success: false, message: 'Invalid credentials' });
    }
    const valid = await bcrypt.compare(password, user.password_hash);
    if (!valid) return res.status(401).json({ success: false, message: 'Invalid credentials' });

    await user.update({ last_login: new Date() });

    // Get companies for this user
    const memberships = await CompanyUser.findAll({
      where: { user_id: user.id, is_active: true },
      include: [{ model: Company, where: { is_active: true } }],
    });

    const token = generateToken(user);
    res.json({
      success: true,
      data: {
        token,
        user: { id: user.id, name: user.name, email: user.email, avatar_url: user.avatar_url },
        companies: memberships.map((m) => ({
          id: m.Company.id, name: m.Company.name,
          logo_url: m.Company.logo_url, role: m.role, currency: m.Company.currency,
        })),
      },
    });
  } catch (err) { next(err); }
};

// GET /api/v1/auth/me
exports.getMe = async (req, res) => {
  const memberships = await CompanyUser.findAll({
    where: { user_id: req.user.id, is_active: true },
    include: [{ model: Company, where: { is_active: true } }],
  });
  res.json({
    success: true,
    data: {
      user: req.user,
      companies: memberships.map((m) => ({
        id: m.Company.id, name: m.Company.name,
        logo_url: m.Company.logo_url, role: m.role, currency: m.Company.currency,
      })),
    },
  });
};

// PUT /api/v1/auth/profile
exports.updateProfile = async (req, res, next) => {
  try {
    const { name, avatar_url } = req.body;
    await req.user.update({ name, avatar_url });
    res.json({ success: true, data: req.user });
  } catch (err) { next(err); }
};

// PUT /api/v1/auth/change-password
exports.changePassword = async (req, res, next) => {
  try {
    const { current_password, new_password } = req.body;
    const user = await User.findByPk(req.user.id);
    const valid = await bcrypt.compare(current_password, user.password_hash);
    if (!valid) return res.status(400).json({ success: false, message: 'Current password incorrect' });
    const password_hash = await bcrypt.hash(new_password, 12);
    await user.update({ password_hash });
    res.json({ success: true, message: 'Password changed successfully' });
  } catch (err) { next(err); }
};

// Helper: setup defaults for a new company
async function setupCompanyDefaults(companyId) {
  const { Sequence, Account, Tax, Currency, PaymentTerm } = require('../models');
  const sequelize = require('../config/database');

  // Document sequences
  const docTypes = [
    { type: 'invoice', prefix: 'INV-' },
    { type: 'estimate', prefix: 'EST-' },
    { type: 'sales_order', prefix: 'SO-' },
    { type: 'purchase_order', prefix: 'PO-' },
    { type: 'bill', prefix: 'BILL-' },
    { type: 'credit_note', prefix: 'CN-' },
    { type: 'vendor_credit', prefix: 'VC-' },
    { type: 'customer_payment', prefix: 'PAY-' },
    { type: 'vendor_payment', prefix: 'VPAY-' },
    { type: 'journal_entry', prefix: 'JE-' },
    { type: 'expense', prefix: 'EXP-' },
  ];
  for (const d of docTypes) {
    await Sequence.create({ company_id: companyId, ...d, next_number: 1 });
  }

  // Default payment terms
  const terms = [
    { name: 'Net 15', days: 15 },
    { name: 'Net 30', days: 30 },
    { name: 'Net 60', days: 60 },
    { name: 'Due on Receipt', days: 0 },
  ];
  for (const t of terms) {
    await PaymentTerm.create({ company_id: companyId, ...t });
  }

  // Default chart of accounts
  const accounts = [
    // Assets
    { account_code: '1000', name: 'Cash and Cash Equivalents', type: 'asset', subtype: 'current', is_system: true },
    { account_code: '1010', name: 'Checking Account', type: 'asset', subtype: 'bank', is_system: true },
    { account_code: '1020', name: 'Savings Account', type: 'asset', subtype: 'bank', is_system: false },
    { account_code: '1100', name: 'Accounts Receivable', type: 'asset', subtype: 'current', is_system: true },
    { account_code: '1200', name: 'Inventory Asset', type: 'asset', subtype: 'current', is_system: false },
    { account_code: '1300', name: 'Prepaid Expenses', type: 'asset', subtype: 'current', is_system: false },
    { account_code: '1500', name: 'Property and Equipment', type: 'asset', subtype: 'fixed', is_system: false },
    { account_code: '1510', name: 'Accumulated Depreciation', type: 'asset', subtype: 'fixed', is_system: false },
    // Liabilities
    { account_code: '2000', name: 'Accounts Payable', type: 'liability', subtype: 'current', is_system: true },
    { account_code: '2100', name: 'Sales Tax Payable', type: 'liability', subtype: 'current', is_system: true },
    { account_code: '2200', name: 'Accrued Liabilities', type: 'liability', subtype: 'current', is_system: false },
    { account_code: '2300', name: 'Deferred Revenue', type: 'liability', subtype: 'current', is_system: false },
    { account_code: '2500', name: 'Long-Term Debt', type: 'liability', subtype: 'long_term', is_system: false },
    // Equity
    { account_code: '3000', name: "Owner's Equity", type: 'equity', subtype: 'equity', is_system: true },
    { account_code: '3100', name: 'Retained Earnings', type: 'equity', subtype: 'equity', is_system: true },
    { account_code: '3200', name: 'Common Stock', type: 'equity', subtype: 'equity', is_system: false },
    // Income
    { account_code: '4000', name: 'Sales Revenue', type: 'income', subtype: 'sales', is_system: true },
    { account_code: '4100', name: 'Service Revenue', type: 'income', subtype: 'sales', is_system: false },
    { account_code: '4200', name: 'Other Income', type: 'income', subtype: 'other', is_system: false },
    { account_code: '4300', name: 'Interest Income', type: 'income', subtype: 'other', is_system: false },
    // COGS
    { account_code: '5000', name: 'Cost of Goods Sold', type: 'cost_of_goods_sold', subtype: 'cogs', is_system: true },
    { account_code: '5100', name: 'Direct Labor', type: 'cost_of_goods_sold', subtype: 'cogs', is_system: false },
    // Expenses
    { account_code: '6000', name: 'Salaries and Wages', type: 'expense', subtype: 'payroll', is_system: false },
    { account_code: '6100', name: 'Rent Expense', type: 'expense', subtype: 'facilities', is_system: false },
    { account_code: '6200', name: 'Utilities', type: 'expense', subtype: 'facilities', is_system: false },
    { account_code: '6300', name: 'Office Supplies', type: 'expense', subtype: 'general', is_system: false },
    { account_code: '6400', name: 'Marketing and Advertising', type: 'expense', subtype: 'marketing', is_system: false },
    { account_code: '6500', name: 'Travel and Entertainment', type: 'expense', subtype: 'travel', is_system: false },
    { account_code: '6600', name: 'Insurance', type: 'expense', subtype: 'general', is_system: false },
    { account_code: '6700', name: 'Depreciation Expense', type: 'expense', subtype: 'general', is_system: false },
    { account_code: '6800', name: 'Professional Services', type: 'expense', subtype: 'general', is_system: false },
    { account_code: '6900', name: 'Bank Charges', type: 'expense', subtype: 'bank', is_system: false },
    { account_code: '7000', name: 'Meals and Entertainment', type: 'expense', subtype: 'general', is_system: false },
    { account_code: '7100', name: 'Telephone and Internet', type: 'expense', subtype: 'general', is_system: false },
    { account_code: '7200', name: 'Repairs and Maintenance', type: 'expense', subtype: 'general', is_system: false },
  ];
  for (const acc of accounts) {
    await Account.create({ company_id: companyId, currency: 'USD', ...acc });
  }

  // Default base currency
  await Currency.create({
    company_id: companyId, code: 'USD', name: 'US Dollar',
    symbol: '$', exchange_rate: 1.0, is_base: true,
  });
}

module.exports.setupCompanyDefaults = setupCompanyDefaults;
