const express = require('express');
const cors = require('cors');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const sqlite3 = require('sqlite3').verbose();
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const path = require('path');
const { v4: uuidv4 } = require('uuid');

const app = express();
const PORT = process.env.PORT || 12004;
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';

// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname, '..')));

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);

// Initialize SQLite database
const db = new sqlite3.Database('./mindshift.db');

// Create tables
db.serialize(() => {
  // Users table
  db.run(`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email TEXT UNIQUE NOT NULL,
    password TEXT NOT NULL,
    name TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    last_login DATETIME
  )`);

  // Mood tracking table
  db.run(`CREATE TABLE IF NOT EXISTS mood_entries (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    mood_type TEXT NOT NULL,
    intensity INTEGER NOT NULL,
    notes TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users (id)
  )`);

  // Thoughts table
  db.run(`CREATE TABLE IF NOT EXISTS thoughts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    situation TEXT NOT NULL,
    automatic_thought TEXT NOT NULL,
    emotion TEXT NOT NULL,
    emotion_intensity INTEGER NOT NULL,
    cognitive_distortion TEXT,
    alternative_thought TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users (id)
  )`);

  // Gratitude entries table
  db.run(`CREATE TABLE IF NOT EXISTS gratitude_entries (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    entry TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users (id)
  )`);

  // Progress tracking table
  db.run(`CREATE TABLE IF NOT EXISTS progress (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    date DATE NOT NULL,
    mood_score INTEGER,
    thoughts_count INTEGER DEFAULT 0,
    gratitude_count INTEGER DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(user_id, date),
    FOREIGN KEY (user_id) REFERENCES users (id)
  )`);

  // Notifications table
  db.run(`CREATE TABLE IF NOT EXISTS notifications (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    title TEXT NOT NULL,
    message TEXT NOT NULL,
    type TEXT DEFAULT 'info',
    read BOOLEAN DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users (id)
  )`);

  // Exercise Logs table
  db.run(`CREATE TABLE IF NOT EXISTS exercise_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    exercise_type TEXT NOT NULL,
    duration INTEGER NOT NULL,
    completed BOOLEAN DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users (id)
  )`);
});

// JWT authentication middleware
function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'Access token required' });
  }

  jwt.verify(token, JWT_SECRET, (err, user) => {
    if (err) {
      return res.status(403).json({ error: 'Invalid token' });
    }
    req.user = user;
    next();
  });
}

// Auth routes
app.post('/api/auth/register', async (req, res) => {
  try {
    const { email, password, name } = req.body;

    if (!email || !password || !name) {
      return res.status(400).json({ error: 'Email, password, and name are required' });
    }

    // Check if user already exists
    db.get('SELECT id FROM users WHERE email = ?', [email], async (err, user) => {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }

      if (user) {
        return res.status(400).json({ error: 'User already exists' });
      }

      // Hash password
      const saltRounds = 10;
      const hashedPassword = await bcrypt.hash(password, saltRounds);

      // Insert new user
      db.run('INSERT INTO users (email, password, name) VALUES (?, ?, ?)', 
        [email, hashedPassword, name], function(err) {
        if (err) {
          return res.status(500).json({ error: 'Database error' });
        }

        // Generate JWT
        const token = jwt.sign(
          { id: this.lastID, email, name },
          JWT_SECRET,
          { expiresIn: '24h' }
        );

        res.status(201).json({
          message: 'User created successfully',
          token,
          user: {
            id: this.lastID,
            email,
            name
          }
        });
      });
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

app.post('/api/auth/login', (req, res) => {
  try {
    const { email, password } = req.body;

    if (!email || !password) {
      return res.status(400).json({ error: 'Email and password are required' });
    }

    // Find user
    db.get('SELECT * FROM users WHERE email = ?', [email], async (err, user) => {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }

      if (!user) {
        return res.status(401).json({ error: 'Invalid credentials' });
      }

      // Check password
      const validPassword = await bcrypt.compare(password, user.password);
      if (!validPassword) {
        return res.status(401).json({ error: 'Invalid credentials' });
      }

      // Update last login
      db.run('UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?', [user.id]);

      // Generate JWT
      const token = jwt.sign(
        { id: user.id, email: user.email, name: user.name },
        JWT_SECRET,
        { expiresIn: '24h' }
      );

      res.json({
        message: 'Login successful',
        token,
        user: {
          id: user.id,
          email: user.email,
          name: user.name
        }
      });
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// Get user profile
app.get('/api/user/profile', authenticateToken, (req, res) => {
  db.get('SELECT id, email, name, created_at, last_login FROM users WHERE id = ?', [req.user.id], (err, user) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    res.json(user);
  });
});

// Mood tracking
app.post('/api/mood/track', authenticateToken, (req, res) => {
  try {
    const { moodType, intensity, notes } = req.body;

    if (!moodType || !intensity || intensity < 1 || intensity > 10) {
      return res.status(400).json({ error: 'Invalid mood data' });
    }

    // Insert mood entry
    db.run('INSERT INTO mood_entries (user_id, mood_type, intensity, notes) VALUES (?, ?, ?, ?)',
      [req.user.id, moodType, intensity, notes || null], function(err) {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }

      // Update or create progress entry for today
      const today = new Date().toISOString().split('T')[0];
      db.run(`INSERT OR REPLACE INTO progress (user_id, date, mood_score, thoughts_count, gratitude_count) 
        VALUES (?, ?, COALESCE((SELECT mood_score FROM progress WHERE user_id = ? AND date = ?), ?), 
        COALESCE((SELECT thoughts_count FROM progress WHERE user_id = ? AND date = ?), 0),
        COALESCE((SELECT gratitude_count FROM progress WHERE user_id = ? AND date = ?), 0))`,
        [req.user.id, today, req.user.id, today, intensity, req.user.id, today, req.user.id, today],
        function(err) {
          if (err) {
            return res.status(500).json({ error: 'Database error' });
          }

          res.status(201).json({
            message: 'Mood tracked successfully',
            entryId: this.lastID
          });
        });
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// Get mood history
app.get('/api/mood/history', authenticateToken, (req, res) => {
  const limit = parseInt(req.query.limit) || 30;
  
  db.all('SELECT * FROM mood_entries WHERE user_id = ? ORDER BY created_at DESC LIMIT ?',
    [req.user.id, limit], (err, entries) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    res.json(entries);
  });
});

// Thought recording
app.post('/api/thoughts', authenticateToken, (req, res) => {
  try {
    const { situation, automaticThought, emotion, emotionIntensity, cognitiveDistortion, alternativeThought } = req.body;

    if (!situation || !automaticThought || !emotion || !emotionIntensity || emotionIntensity < 1 || emotionIntensity > 10) {
      return res.status(400).json({ error: 'Invalid thought data' });
    }

    // Insert thought entry
    db.run('INSERT INTO thoughts (user_id, situation, automatic_thought, emotion, emotion_intensity, cognitive_distortion, alternative_thought) VALUES (?, ?, ?, ?, ?, ?, ?)',
      [req.user.id, situation, automaticThought, emotion, emotionIntensity, cognitiveDistortion || null, alternativeThought || null], function(err) {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }

      // Update progress entry for today
      const today = new Date().toISOString().split('T')[0];
      db.run(`INSERT OR REPLACE INTO progress (user_id, date, mood_score, thoughts_count, gratitude_count) 
        VALUES (?, ?, COALESCE((SELECT mood_score FROM progress WHERE user_id = ? AND date = ?), 0), 
        COALESCE((SELECT thoughts_count FROM progress WHERE user_id = ? AND date = ?), 0) + 1,
        COALESCE((SELECT gratitude_count FROM progress WHERE user_id = ? AND date = ?), 0))`,
        [req.user.id, today, req.user.id, today, req.user.id, today, req.user.id, today],
        function(err) {
          if (err) {
            return res.status(500).json({ error: 'Database error' });
          }

          res.status(201).json({
            message: 'Thought recorded successfully',
            entryId: this.lastID
          });
        });
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// Get thoughts history
app.get('/api/thoughts', authenticateToken, (req, res) => {
  const limit = parseInt(req.query.limit) || 30;
  
  db.all('SELECT * FROM thoughts WHERE user_id = ? ORDER BY created_at DESC LIMIT ?',
    [req.user.id, limit], (err, entries) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    res.json(entries);
  });
});

// Gratitude entries
app.post('/api/gratitude', authenticateToken, (req, res) => {
  try {
    const { entry } = req.body;

    if (!entry || entry.trim() === '') {
      return res.status(400).json({ error: 'Gratitude entry is required' });
    }

    // Insert gratitude entry
    db.run('INSERT INTO gratitude_entries (user_id, entry) VALUES (?, ?)',
      [req.user.id, entry], function(err) {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }

      // Update progress entry for today
      const today = new Date().toISOString().split('T')[0];
      db.run(`INSERT OR REPLACE INTO progress (user_id, date, mood_score, thoughts_count, gratitude_count) 
        VALUES (?, ?, COALESCE((SELECT mood_score FROM progress WHERE user_id = ? AND date = ?), 0), 
        COALESCE((SELECT thoughts_count FROM progress WHERE user_id = ? AND date = ?), 0),
        COALESCE((SELECT gratitude_count FROM progress WHERE user_id = ? AND date = ?), 0) + 1)`,
        [req.user.id, today, req.user.id, today, req.user.id, today, req.user.id, today],
        function(err) {
          if (err) {
            return res.status(500).json({ error: 'Database error' });
          }

          res.status(201).json({
            message: 'Gratitude entry added successfully',
            entryId: this.lastID
          });
        });
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// Log Exercise Session
app.post('/api/exercises', authenticateToken, (req, res) => {
  try {
    const { exerciseType, duration } = req.body;

    if (!exerciseType || !duration) {
      return res.status(400).json({ error: 'Type and duration required' });
    }

    db.run('INSERT INTO exercise_logs (user_id, exercise_type, duration) VALUES (?, ?, ?)',
      [req.user.id, exerciseType, duration], function(err) {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }
      res.status(201).json({ success: true, id: this.lastID });
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// Get gratitude entries
app.get('/api/gratitude', authenticateToken, (req, res) => {
  const limit = parseInt(req.query.limit) || 30;
  
  db.all('SELECT * FROM gratitude_entries WHERE user_id = ? ORDER BY created_at DESC LIMIT ?',
    [req.user.id, limit], (err, entries) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    res.json(entries);
  });
});

// Get progress data
app.get('/api/progress', authenticateToken, (req, res) => {
  const days = parseInt(req.query.days) || 30;
  
  db.all('SELECT * FROM progress WHERE user_id = ? ORDER BY date DESC LIMIT ?',
    [req.user.id, days], (err, entries) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    res.json(entries);
  });
});

// Get dashboard stats
app.get('/api/dashboard/stats', authenticateToken, (req, res) => {
  const today = new Date().toISOString().split('T')[0];
  
  // Get today's progress
  db.get('SELECT * FROM progress WHERE user_id = ? AND date = ?', [req.user.id, today], (err, todayProgress) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    
    // Get this week's mood entries
    const weekAgo = new Date();
    weekAgo.setDate(weekAgo.getDate() - 7);
    const weekAgoStr = weekAgo.toISOString().split('T')[0];
    
    db.all('SELECT AVG(intensity) as avgMood, COUNT(*) as count FROM mood_entries WHERE user_id = ? AND created_at >= ?',
      [req.user.id, weekAgoStr], (err, weekMood) => {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }
      
      // Get total counts
      db.get(`SELECT 
        (SELECT COUNT(*) FROM mood_entries WHERE user_id = ?) as totalMoods,
        (SELECT COUNT(*) FROM thoughts WHERE user_id = ?) as totalThoughts,
        (SELECT COUNT(*) FROM gratitude_entries WHERE user_id = ?) as totalGratitude,
        (SELECT COUNT(*) FROM exercise_logs WHERE user_id = ?) as totalSessions`,
        [req.user.id, req.user.id, req.user.id, req.user.id], (err, totals) => {
        if (err) {
          return res.status(500).json({ error: 'Database error' });
        }
        
        res.json({
          today: todayProgress || { mood_score: 0, thoughts_count: 0, gratitude_count: 0 },
          week: {
            avgMood: weekMood[0].avgMood || 0,
            moodCount: weekMood[0].count || 0
          },
          totals: totals
        });
      });
    });
  });
});

// Notifications
app.get('/api/notifications', authenticateToken, (req, res) => {
  db.all('SELECT * FROM notifications WHERE user_id = ? ORDER BY created_at DESC', [req.user.id], (err, notifications) => {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    res.json(notifications);
  });
});

app.post('/api/notifications', authenticateToken, (req, res) => {
  const { title, message, type } = req.body;
  
  if (!title || !message) {
    return res.status(400).json({ error: 'Title and message are required' });
  }

  db.run('INSERT INTO notifications (user_id, title, message, type) VALUES (?, ?, ?, ?)',
    [req.user.id, title, message, type || 'info'], function(err) {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    
    // Return the created notification
    db.get('SELECT * FROM notifications WHERE id = ?', [this.lastID], (err, notification) => {
      if (err) {
        return res.status(500).json({ error: 'Database error' });
      }
      res.status(201).json(notification);
    });
  });
});

app.put('/api/notifications/:id/read', authenticateToken, (req, res) => {
  const notificationId = req.params.id;
  
  db.run('UPDATE notifications SET read = 1 WHERE id = ? AND user_id = ?',
    [notificationId, req.user.id], function(err) {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    if (this.changes === 0) {
      return res.status(404).json({ error: 'Notification not found' });
    }
    res.json({ success: true });
  });
});

app.delete('/api/notifications/:id', authenticateToken, (req, res) => {
  const notificationId = req.params.id;
  
  db.run('DELETE FROM notifications WHERE id = ? AND user_id = ?',
    [notificationId, req.user.id], function(err) {
    if (err) {
      return res.status(500).json({ error: 'Database error' });
    }
    if (this.changes === 0) {
      return res.status(404).json({ error: 'Notification not found' });
    }
    res.json({ success: true });
  });
});

// Start server
app.listen(PORT, () => {
  console.log(`MindShift server running on port ${PORT}`);
});