require('dotenv').config();
const express = require('express');
const path = require('path');
const fs = require('fs').promises;
const fsSync = require('fs');
const cors = require('cors');
const compression = require('compression');
const multer = require('multer');
const cookieParser = require('cookie-parser');

const app = express();
const PORT = process.env.PORT || 3000;
const DATA_DIR = path.join(__dirname, 'data');
const UPLOADS_DIR = path.join(__dirname, 'uploads');
const SESSIONS_DIR = path.join(__dirname, 'sessions');

const BOOT_TIME = Date.now();

// Middleware
app.use(compression());
app.use(cors({ origin: true, credentials: true }));
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
app.use(cookieParser());

// Ensure directories exist
function ensureDirs() {
  [DATA_DIR, UPLOADS_DIR, SESSIONS_DIR].forEach(dir => {
    if (!fsSync.existsSync(dir)) {
      fsSync.mkdirSync(dir, { recursive: true });
    }
  });
}
ensureDirs();

// Helper functions
const GLOBAL_KEYS = [
  "users", "roles", "rolePermissions", "companySettings", "projects", "tasks", "expenses", 
  "clients", "engineers", "employees", "departments", "jobs", "candidates", "documents", 
  "folders", "bankDetails", "currencies", "leads"
].map(k => k.toLowerCase());

const OBJECT_KEYS = ["rolepermissions", "companysettings"];

async function updateLastGlobalChange() {
  const now = Date.now();
  try {
    await fs.writeFile(path.join(DATA_DIR, 'last_change.txt'), now.toString(), 'utf8');
    return now;
  } catch (e) {
    return now;
  }
}

async function readData(key, defaultValue = []) {
  const normalizedKey = key.toLowerCase();
  const filePath = path.join(DATA_DIR, `${normalizedKey}.json`);
  try {
    const data = await fs.readFile(filePath, 'utf8');
    let parsed = JSON.parse(data);
    
    if (OBJECT_KEYS.includes(normalizedKey) && Array.isArray(parsed)) {
      parsed = parsed[0] || defaultValue;
    } else if (!OBJECT_KEYS.includes(normalizedKey) && !Array.isArray(parsed) && parsed !== null) {
      parsed = [parsed];
    }
    
    return parsed;
  } catch (err) {
    return defaultValue;
  }
}

async function writeData(key, data) {
  const normalizedKey = key.toLowerCase();
  const filePath = path.join(DATA_DIR, `${normalizedKey}.json`);
  await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf8');
  const lastChange = await updateLastGlobalChange();
  return lastChange;
}

// Multer setup for uploads
const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, UPLOADS_DIR),
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
    cb(null, uniqueSuffix + '-' + file.originalname);
  }
});
const upload = multer({ storage });

const getSessionPath = (sessionId) => path.join(SESSIONS_DIR, `${sessionId}.json`);

// Auth helpers
async function getUserId(req) {
  const sessionId = req.headers['x-session-id'] || req.cookies.sessionId;
  if (!sessionId) return null;
  const sessionPath = getSessionPath(sessionId);
  try {
    const content = await fs.readFile(sessionPath, "utf-8");
    const sessionData = JSON.parse(content);
    return sessionData.uid || sessionData.id || (sessionData.profile && (sessionData.profile.uid || sessionData.profile.id));
  } catch (e) {
    return null;
  }
}

// API Routes
app.get('/api/health', async (req, res) => {
  let lastChange = Date.now();
  try {
    const content = await fs.readFile(path.join(DATA_DIR, 'last_change.txt'), 'utf8');
    lastChange = parseInt(content);
  } catch (e) {}
  
  res.json({ 
    status: 'ok', 
    timestamp: new Date().toISOString(),
    lastChange,
    bootTime: BOOT_TIME
  });
});

// Data API
app.get('/api/data/:key', async (req, res) => {
  const { key } = req.params;
  const normalizedKey = key.toLowerCase();
  const userId = await getUserId(req);
  
  if (!userId && !GLOBAL_KEYS.includes(normalizedKey)) {
    return res.json([]);
  }

  const data = await readData(key);
  res.json(data);
});

app.post('/api/data/:key', async (req, res) => {
  const { key } = req.params;
  const userId = await getUserId(req);
  
  if (!userId && !["users"].includes(key.toLowerCase())) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  try {
    const lastChange = await writeData(key, req.body);
    res.json({ success: true, lastChange });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
});

// Auth Routes
app.get('/api/auth/user', async (req, res) => {
  const sessionId = req.headers['x-session-id'] || req.cookies.sessionId;
  if (!sessionId) return res.json(null);
  try {
    const data = await fs.readFile(getSessionPath(sessionId), 'utf8');
    res.json(JSON.parse(data));
  } catch (e) {
    res.json(null);
  }
});

app.post('/api/auth/user', async (req, res) => {
  const sessionId = req.headers['x-session-id'] || req.cookies.sessionId || (Math.random().toString(36).substring(2) + Date.now().toString(36));
  res.cookie('sessionId', sessionId, { 
    httpOnly: true, 
    secure: true,
    sameSite: 'none',
    maxAge: 30 * 24 * 60 * 60 * 1000
  });
  try {
    await fs.writeFile(getSessionPath(sessionId), JSON.stringify(req.body, null, 2), 'utf8');
    res.json({ success: true, sessionId });
  } catch (error) {
    res.status(500).json({ success: false, error: 'Failed to save session' });
  }
});

app.post('/api/auth/logout', async (req, res) => {
  const sessionId = req.headers['x-session-id'] || req.cookies.sessionId;
  if (sessionId) {
    try { await fs.unlink(getSessionPath(sessionId)); } catch (e) {}
  }
  res.clearCookie('sessionId', { httpOnly: true, secure: true, sameSite: 'none' });
  res.json({ success: true });
});

// Uploads
app.use('/uploads', express.static(UPLOADS_DIR));
app.post('/api/upload', upload.single('file'), (req, res) => {
  if (!req.file) return res.status(400).json({ error: 'No file uploaded' });
  res.json({
    name: req.file.originalname,
    url: `/uploads/${req.file.filename}`,
    size: `${(req.file.size / 1024).toFixed(2)} KB`,
    type: req.file.mimetype,
    uploadedAt: new Date().toISOString(),
  });
});

// Static files (React build)
const distPath = path.join(__dirname, 'dist');
app.use(express.static(distPath));

// SPA Fallback
app.get('*', (req, res) => {
  res.sendFile(path.join(distPath, 'index.html'));
});

// Start
app.listen(PORT, async () => {
  console.log(`Server running on port ${PORT}`);
  try {
    await updateLastGlobalChange();
  } catch (e) {}
});
