const path = require('path');
const express = require('express');
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);
const expressLayouts = require('express-ejs-layouts');
const methodOverride = require('method-override');
const helmet = require('helmet');
const flash = require('connect-flash');
require('dotenv').config();

const dbOptions = require('./src/config/dbOptions');
const db = require('./src/config/db');
const { ensureDefaultSettings } = require('./src/models/settingsModel');
const authRoutes = require('./src/routes/auth.routes');
const dashboardRoutes = require('./src/routes/dashboard.routes');
const settingsRoutes = require('./src/routes/settings.routes');
const invoiceRoutes = require('./src/routes/invoice.routes');
const reportRoutes = require('./src/routes/report.routes');

const app = express();
const basePath = (process.env.BASE_PATH || '').replace(/\/$/, '');
const sessionStore = db.isSQLite ? undefined : new MySQLStore(dbOptions);
app.locals.basePath = basePath;

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'src', 'views'));
app.use(expressLayouts);
app.set('layout', 'layout');
app.set('layout extractScripts', true);

app.use(helmet({ contentSecurityPolicy: false }));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(methodOverride('_method'));
app.use('/public', express.static(path.join(__dirname, 'public')));
app.use((req, res, next) => {
  const originalRedirect = res.redirect.bind(res);
  res.redirect = (statusOrUrl, maybeUrl) => {
    const status = typeof statusOrUrl === 'number' ? statusOrUrl : undefined;
    const redirectUrl = status ? maybeUrl : statusOrUrl;
    const resolvedUrl = basePath && typeof redirectUrl === 'string' && redirectUrl.startsWith('/') && !redirectUrl.startsWith(basePath)
      ? `${basePath}${redirectUrl}`
      : redirectUrl;
    return status ? originalRedirect(status, resolvedUrl) : originalRedirect(resolvedUrl);
  };
  next();
});

app.use(session({
  key: 'ecofina.sid',
  secret: process.env.SESSION_SECRET || 'replace-this-secret',
  store: sessionStore,
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    sameSite: 'lax',
    secure: process.env.NODE_ENV === 'production',
    maxAge: 1000 * 60 * 60 * 8
  }
}));
app.use(flash());

app.use((req, res, next) => {
  res.locals.user = req.session.user || null;
  res.locals.success = req.flash('success');
  res.locals.error = req.flash('error');
  res.locals.currentPath = req.path;
  res.locals.basePath = basePath;
  res.locals.url = (target = '/') => {
    const value = String(target || '/');
    if (!basePath || !value.startsWith('/')) return value;
    return value.startsWith(basePath) ? value : `${basePath}${value}`;
  };
  res.locals.formatDate = (value) => {
    if (!value) return '';
    if (value instanceof Date) return value.toISOString().slice(0, 10);
    return String(value).slice(0, 10);
  };
  next();
});

app.get('/', (req, res) => {
  if (req.session.user) return res.redirect('/dashboard');
  return res.redirect('/login');
});

app.use('/', authRoutes);
app.use('/dashboard', dashboardRoutes);
app.use('/settings', settingsRoutes);
app.use('/invoices', invoiceRoutes);
app.use('/reports', reportRoutes);

app.use((req, res) => {
  res.status(404).render('errors/404', { title: 'Page not found' });
});

app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).render('errors/500', { title: 'Server error', message: err.message });
});

const port = process.env.PORT || 3000;

db.init()
  .then(() => ensureDefaultSettings())
  .then(() => {
    app.listen(port, () => console.log(`Ecofina billing app running on port ${port}`));
  })
  .catch((error) => {
    console.error('Unable to start application:', error);
    process.exit(1);
  });
