require('dotenv').config();
const express = require('express');
const cors = require('cors');
const { createDatabase } = require('./database/createDb');
const cookieParser = require('cookie-parser');
const authMiddleware = require('./middleware/authMiddleware');
const { createRateLimiter } = require('./middleware/rateLimiter');
// add logger (now with setters/getter)
const { logger, requestLogger, setLogLevel, setTransportLevel, getLoggerLevels } = require('./middleware/logger');

// ADD: import permission initializer and admin-creation script
const permissionsInit = require('./scripts/initPermissions');
const createAdminUser = require('./scripts/createAdminUser');
const createCompanyUser = require('./scripts/createCompanyUser');
const createPersonalUser = require('./scripts/createPersonalUser');
const createGuestUser = require('./scripts/createGuestUser');
const RenewalCronService = require('./services/abonemments/RenewalCronService');

const app = express();
const PORT = process.env.PORT || 3001;

// Increase body size limits for base64 payloads (e.g. QR code images)
const JSON_LIMIT = process.env.JSON_LIMIT || '2mb';

// CORS configuration
const ALLOWED_ORIGINS = (process.env.CORS_ALLOWED_ORIGINS)
  .split(',')
  .map(o => o.trim());

const corsOptions = {
  origin: function (origin, callback) {
    if (!origin) return callback(null, true); // non-browser clients
    if (ALLOWED_ORIGINS.includes(origin)) {
      return callback(null, true);
    }
    return callback(new Error('Not allowed by CORS'));
  },
  credentials: true,
  methods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'],
  allowedHeaders: ['Content-Type','Authorization'],
  exposedHeaders: []
};

app.use(cors(corsOptions));

// Middleware
app.use(express.json({ limit: JSON_LIMIT }));
app.use(express.urlencoded({ extended: true, limit: JSON_LIMIT }));
app.use(cookieParser());

// -- Replace inline console logging with structured request logger --
app.use(requestLogger);
// -- end logging middleware --

// Basic route to handle requests from frontend
app.get('/', (req, res) => {
  res.json({ message: 'Central server is running and ready to receive requests' });
});

// Example API endpoint
app.post('/api/data', (req, res) => {
	logger.debug('Received request from frontend', { requestId: req.id, body: req.body && typeof req.body === 'object' ? '[object]' : req.body });
	res.json({
		success: true,
		message: 'Data received successfully',
		timestamp: new Date().toISOString()
	});
});

// Test endpoint for frontend
app.get('/api/test', (req, res) => {
	logger.info('Test request received from frontend', { requestId: req.id });
	res.json({
		success: true,
		message: 'Backend connection successful!',
		timestamp: new Date().toISOString(),
		server: 'Central Server'
	});
});

// Protected route example
app.use('/api/protected', authMiddleware, (req, res) => {
  res.json({ success: true, message: 'Access granted', user: req.user });
});

// Import and mount the new verb-specific routers
const getRoutes = require('./routes/getRoutes');
const postRoutes = require('./routes/postRoutes');
const putRoutes = require('./routes/putRoutes');
const patchRoutes = require('./routes/patchRoutes');
const deleteRoutes = require('./routes/deleteRoutes'); // added

app.use('/api', getRoutes);
app.use('/api', postRoutes);
app.use('/api', putRoutes);
app.use('/api', patchRoutes);
app.use('/api', deleteRoutes);

logger.info('🛣️ Verb-specific routes configured and ready');

// Insert admin endpoint for dynamic log-level control
// Requires authenticated user and admin role
app.post('/api/admin/log-level', authMiddleware, (req, res) => {
	// Basic auth + role check (assumes authMiddleware sets req.user)
	if (!req.user || req.user.role !== 'admin') {
		logger.warn('admin:forbidden_log_level_change', { requestId: req.id, user: req.user && req.user.id });
		return res.status(403).json({ success: false, message: 'Forbidden' });
	}

	const { level, transport } = req.body || {};
	const allowedLevels = ['error','warn','info','http','verbose','debug','silly'];

	if (!level || typeof level !== 'string' || !allowedLevels.includes(level)) {
		return res.status(400).json({ success: false, message: `Invalid level. Allowed: ${allowedLevels.join(', ')}` });
	}

	let ok = false;
	if (transport && typeof transport === 'string') {
		// set specific transport (e.g. 'console' or 'file' or class name)
		ok = setTransportLevel(transport, level);
	} else {
		// set global level (affects logger and all transports)
		ok = setLogLevel(level);
	}

	const current = getLoggerLevels();
	if (!ok) {
		logger.warn('admin:log_level_change_failed', { requestId: req.id, userId: req.user && req.user.id, level, transport });
		return res.status(500).json({ success: false, message: 'Failed to apply log level', current });
	}

	logger.info('admin:log_level_changed', { requestId: req.id, userId: req.user && req.user.id, level, transport });
	return res.status(200).json({ success: true, message: 'Log level updated', current });
});

// Express error handler (logs structured error and returns safe response)
function errorHandler(err, req, res, next) {
	logger.error('http:error', {
		message: err && err.message,
		stack: err && err.stack,
		requestId: req && req.id,
		method: req && req.method,
		url: req && req.originalUrl,
		user: req && req.user ? { id: req.user.id, email: req.user.email } : undefined
	});
	const status = (err && err.status) || 500;
	const safeMessage = process.env.NODE_ENV === 'development' ? (err && err.message) : 'Internal Server Error';
	res.status(status).json({ success: false, message: safeMessage });
}
app.use(errorHandler);

// register global error / process handlers
process.on('uncaughtException', (err) => {
	try {
		logger.error('uncaughtException', { message: err.message, stack: err.stack });
	} catch (e) {
		console.error('Failed to log uncaughtException', e);
	}
	// optionally flush and exit for safety
	setTimeout(() => process.exit(1), 1000);
});

process.on('unhandledRejection', (reason) => {
	try {
		logger.error('unhandledRejection', { reason: reason && reason.stack ? reason.stack : reason });
	} catch (e) {
		console.error('Failed to log unhandledRejection', e);
	}
	// optional: exit or let process continue based on policy
});

// Start server with database initialization
async function startServer() {
	try {
		logger.info('🔄 Initializing server...');
		
		// Initialize database first
		await createDatabase();

		// Initialize permissions
		await permissionsInit();

		// Create admin user
		await createAdminUser();

		// Create company user
		await createCompanyUser();

		// Create personal user
		await createPersonalUser();

		// Create guest user
		await createGuestUser();

		// Start automatic subscription renewal cron job
		const renewalCron = new RenewalCronService();
		renewalCron.start();

		// Start the server
		app.listen(PORT, () => {
			const host = process.env.HOST || 'localhost';
			const url = `http://${host}:${PORT}`;
			logger.info('🚀 Central server running', { url, port: PORT });
			logger.info('📡 Waiting for requests from frontend...');
			logger.info('💾 Database initialized and ready');
		});
		
	} catch (error) {
		logger.error('💥 Failed to start server', { message: error.message, stack: error.stack });
		process.exit(1);
	}
}

// Start everything in order
startServer();