import fs from 'fs';
import path from 'path';

const baseDir = './backend';

// Create directories
const dirs = [
  `${baseDir}/src/routes`,
];

dirs.forEach(dir => {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
    console.log(`Created directory: ${dir}`);
  }
});

// package.json
fs.writeFileSync(`${baseDir}/package.json`, JSON.stringify({
  "name": "photobooth-backend",
  "version": "1.0.0",
  "type": "module",
  "main": "src/server.js",
  "scripts": {
    "start": "node src/server.js",
    "dev": "node --watch src/server.js"
  },
  "keywords": ["photobooth", "express", "mysql"],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "express": "^4.18.2",
    "cors": "^2.8.5",
    "dotenv": "^16.3.1",
    "mysql2": "^3.6.5",
    "jsonwebtoken": "^9.1.0",
    "bcryptjs": "^2.4.3",
    "uuid": "^9.0.1",
    "express-async-errors": "^3.1.1",
    "multer": "^1.4.5-lts.1"
  },
  "devDependencies": {}
}, null, 2));
console.log('Created package.json');

// .env.example
fs.writeFileSync(`${baseDir}/.env.example`, `# Backend API
NODE_ENV=production
PORT=3000

# Database
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=photobooth
DB_USER=photobooth_app
DB_PASSWORD=your_app_password_here

# JWT
JWT_SECRET=your_jwt_secret_here_change_in_production
JWT_EXPIRY=15m
REFRESH_TOKEN_EXPIRY=7d

# Frontend
FRONTEND_URL=http://localhost:5173
BACKEND_URL=http://localhost:3000

# File storage
UPLOADS_DIR=./uploads
MAX_FILE_SIZE=10485760
`);
console.log('Created .env.example');

// src/db.js
fs.writeFileSync(`${baseDir}/src/db.js`, `import mysql from 'mysql2/promise'
import dotenv from 'dotenv'

dotenv.config()

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  port: process.env.DB_PORT,
  database: process.env.DB_NAME,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0,
})

export async function query(sql, values) {
  const connection = await pool.getConnection()
  try {
    const [results] = await connection.execute(sql, values)
    return results
  } finally {
    connection.release()
  }
}

export async function getConnection() {
  return pool.getConnection()
}

export default pool
`);
console.log('Created src/db.js');

// src/jwt.js
fs.writeFileSync(`${baseDir}/src/jwt.js`, `import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'

dotenv.config()

const JWT_SECRET = process.env.JWT_SECRET || 'change-me-in-production'
const JWT_EXPIRY = process.env.JWT_EXPIRY || '15m'
const REFRESH_TOKEN_EXPIRY = process.env.REFRESH_TOKEN_EXPIRY || '7d'

export function createAccessToken(userId) {
  return jwt.sign({ userId }, JWT_SECRET, { expiresIn: JWT_EXPIRY })
}

export function createRefreshToken() {
  return jwt.sign({ refreshToken: true }, JWT_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRY })
}

export function verifyToken(token) {
  try {
    return jwt.verify(token, JWT_SECRET)
  } catch {
    return null
  }
}

export function decodeToken(token) {
  try {
    return jwt.decode(token)
  } catch {
    return null
  }
}
`);
console.log('Created src/jwt.js');

// src/models.js
fs.writeFileSync(`${baseDir}/src/models.js`, `import { query } from './db.js'
import bcryptjs from 'bcryptjs'

// User model
export const User = {
  async findById(userId) {
    const results = await query('SELECT id, email, username, created_at FROM users WHERE id = ?', [userId])
    return results[0] || null
  },

  async findByEmail(email) {
    const results = await query('SELECT * FROM users WHERE email = ?', [email])
    return results[0] || null
  },

  async findByUsername(username) {
    const results = await query('SELECT * FROM users WHERE username = ?', [username])
    return results[0] || null
  },

  async create(email, username, passwordHash) {
    const id = crypto.randomUUID()
    await query('INSERT INTO users (id, email, username, password_hash) VALUES (?, ?, ?, ?)', [id, email, username, passwordHash])
    return this.findById(id)
  },

  async verifyPassword(user, password) {
    return bcryptjs.compare(password, user.password_hash)
  },

  async updateLastLogin(userId) {
    await query('UPDATE users SET last_login = NOW() WHERE id = ?', [userId])
  },
}

// Session model
export const Session = {
  async create(sessionId, eventId, createdBy, name) {
    await query('INSERT INTO photo_sessions (id, event_id, created_by, session_name) VALUES (?, ?, ?, ?)', [sessionId, eventId, createdBy, name])
    return this.findById(sessionId)
  },

  async findById(sessionId) {
    const results = await query('SELECT * FROM photo_sessions WHERE id = ?', [sessionId])
    return results[0] || null
  },

  async findByEvent(eventId) {
    return query('SELECT * FROM photo_sessions WHERE event_id = ? ORDER BY created_at DESC', [eventId])
  },

  async update(sessionId, updates) {
    const fields = Object.keys(updates).map(k => \`\${k} = ?\`).join(', ')
    const values = Object.values(updates)
    values.push(sessionId)
    await query(\`UPDATE photo_sessions SET \${fields} WHERE id = ?\`, values)
    return this.findById(sessionId)
  },

  async delete(sessionId) {
    await query('DELETE FROM photo_sessions WHERE id = ?', [sessionId])
  },
}

// Photo model
export const Photo = {
  async create(photoId, sessionId, fileName, filePath, fileSize, uploadedAt) {
    await query('INSERT INTO photos (id, session_id, file_name, file_path, file_size, uploaded_at) VALUES (?, ?, ?, ?, ?, ?)', 
      [photoId, sessionId, fileName, filePath, fileSize, uploadedAt])
    return this.findById(photoId)
  },

  async findById(photoId) {
    const results = await query('SELECT * FROM photos WHERE id = ?', [photoId])
    return results[0] || null
  },

  async findBySession(sessionId) {
    return query('SELECT * FROM photos WHERE session_id = ? ORDER BY uploaded_at DESC', [sessionId])
  },

  async delete(photoId) {
    await query('DELETE FROM photos WHERE id = ?', [photoId])
  },

  async getCount(sessionId) {
    const results = await query('SELECT COUNT(*) as count FROM photos WHERE session_id = ?', [sessionId])
    return results[0]?.count || 0
  },
}

// Event model
export const Event = {
  async create(eventId, createdBy, eventName, description) {
    await query('INSERT INTO events (id, created_by, event_name, description) VALUES (?, ?, ?, ?)', [eventId, createdBy, eventName, description])
    return this.findById(eventId)
  },

  async findById(eventId) {
    const results = await query('SELECT * FROM events WHERE id = ?', [eventId])
    return results[0] || null
  },

  async findByUser(userId) {
    return query('SELECT * FROM events WHERE created_by = ? ORDER BY created_at DESC', [userId])
  },

  async update(eventId, updates) {
    const fields = Object.keys(updates).map(k => \`\${k} = ?\`).join(', ')
    const values = Object.values(updates)
    values.push(eventId)
    await query(\`UPDATE events SET \${fields} WHERE id = ?\`, values)
    return this.findById(eventId)
  },

  async delete(eventId) {
    await query('DELETE FROM events WHERE id = ?', [eventId])
  },
}
`);
console.log('Created src/models.js');

// src/routes/auth.js
fs.writeFileSync(`${baseDir}/src/routes/auth.js`, `import { Router } from 'express'
import { User } from '../models.js'
import { createAccessToken, createRefreshToken, verifyToken } from '../jwt.js'
import bcryptjs from 'bcryptjs'
import { v4 as uuidv4 } from 'uuid'

const router = Router()

// Register
router.post('/register', async (req, res) => {
  const { email, username, password } = req.body

  if (!email || !username || !password) {
    return res.status(400).json({ error: 'Missing required fields' })
  }

  try {
    const existingEmail = await User.findByEmail(email)
    if (existingEmail) {
      return res.status(400).json({ error: 'Email already registered' })
    }

    const existingUser = await User.findByUsername(username)
    if (existingUser) {
      return res.status(400).json({ error: 'Username already taken' })
    }

    const passwordHash = await bcryptjs.hash(password, 10)
    const user = await User.create(email, username, passwordHash)

    const accessToken = createAccessToken(user.id)
    const refreshToken = createRefreshToken()

    res.json({
      user: {
        id: user.id,
        email: user.email,
        username: user.username,
      },
      accessToken,
      refreshToken,
    })
  } catch (error) {
    res.status(500).json({ error: error.message })
  }
})

// Login
router.post('/login', async (req, res) => {
  const { email, password } = req.body

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

  try {
    const user = await User.findByEmail(email)
    if (!user) {
      return res.status(401).json({ error: 'Invalid email or password' })
    }

    const valid = await User.verifyPassword(user, password)
    if (!valid) {
      return res.status(401).json({ error: 'Invalid email or password' })
    }

    await User.updateLastLogin(user.id)

    const accessToken = createAccessToken(user.id)
    const refreshToken = createRefreshToken()

    res.json({
      user: {
        id: user.id,
        email: user.email,
        username: user.username,
      },
      accessToken,
      refreshToken,
    })
  } catch (error) {
    res.status(500).json({ error: error.message })
  }
})

// Refresh token
router.post('/refresh', (req, res) => {
  const { refreshToken } = req.body

  if (!refreshToken) {
    return res.status(400).json({ error: 'Refresh token required' })
  }

  const decoded = verifyToken(refreshToken)
  if (!decoded || !decoded.userId) {
    return res.status(401).json({ error: 'Invalid refresh token' })
  }

  const newAccessToken = createAccessToken(decoded.userId)
  res.json({ accessToken: newAccessToken })
})

// Logout (stateless, just return success)
router.post('/logout', (req, res) => {
  res.json({ message: 'Logged out successfully' })
})

export default router
`);
console.log('Created src/routes/auth.js');

// src/routes/media.js
fs.writeFileSync(`${baseDir}/src/routes/media.js`, `import { Router } from 'express'
import multer from 'multer'
import path from 'path'
import fs from 'fs'
import { v4 as uuidv4 } from 'uuid'
import { Photo, Session } from '../models.js'
import { authenticateToken } from '../middleware.js'

const router = Router()

// Configure multer for file uploads
const uploadsDir = process.env.UPLOADS_DIR || './uploads'
if (!fs.existsSync(uploadsDir)) {
  fs.mkdirSync(uploadsDir, { recursive: true })
}

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, uploadsDir)
  },
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname)
    const filename = \`\${uuidv4()}\${ext}\`
    cb(null, filename)
  },
})

const upload = multer({
  storage,
  limits: { fileSize: parseInt(process.env.MAX_FILE_SIZE) || 10485760 },
  fileFilter: (req, file, cb) => {
    const allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
    if (allowedMimes.includes(file.mimetype)) {
      cb(null, true)
    } else {
      cb(new Error('Invalid file type'))
    }
  },
})

// Upload photo
router.post('/upload/:sessionId', authenticateToken, upload.single('photo'), async (req, res) => {
  try {
    const { sessionId } = req.params

    const session = await Session.findById(sessionId)
    if (!session) {
      if (req.file) fs.unlinkSync(req.file.path)
      return res.status(404).json({ error: 'Session not found' })
    }

    const photoId = uuidv4()
    const photo = await Photo.create(
      photoId,
      sessionId,
      req.file.originalname,
      req.file.path,
      req.file.size,
      new Date()
    )

    res.json(photo)
  } catch (error) {
    if (req.file) fs.unlinkSync(req.file.path)
    res.status(500).json({ error: error.message })
  }
})

// Get photos for session
router.get('/session/:sessionId', authenticateToken, async (req, res) => {
  try {
    const { sessionId } = req.params
    const photos = await Photo.findBySession(sessionId)
    res.json(photos)
  } catch (error) {
    res.status(500).json({ error: error.message })
  }
})

// Delete photo
router.delete('/:photoId', authenticateToken, async (req, res) => {
  try {
    const { photoId } = req.params

    const photo = await Photo.findById(photoId)
    if (!photo) {
      return res.status(404).json({ error: 'Photo not found' })
    }

    if (fs.existsSync(photo.file_path)) {
      fs.unlinkSync(photo.file_path)
    }

    await Photo.delete(photoId)
    res.json({ message: 'Photo deleted' })
  } catch (error) {
    res.status(500).json({ error: error.message })
  }
})

export default router
`);
console.log('Created src/routes/media.js');

// src/middleware.js
fs.writeFileSync(`${baseDir}/src/middleware.js`, `import { verifyToken } from './jwt.js'

export 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' })
  }

  const decoded = verifyToken(token)
  if (!decoded) {
    return res.status(403).json({ error: 'Invalid or expired token' })
  }

  req.userId = decoded.userId
  next()
}

export function errorHandler(err, req, res, next) {
  console.error(err)
  res.status(err.status || 500).json({ error: err.message || 'Internal server error' })
}
`);
console.log('Created src/middleware.js');

// src/server.js
fs.writeFileSync(`${baseDir}/src/server.js`, `import express from 'express'
import cors from 'cors'
import 'express-async-errors'
import dotenv from 'dotenv'
import authRoutes from './routes/auth.js'
import mediaRoutes from './routes/media.js'
import { errorHandler } from './middleware.js'

dotenv.config()

const app = express()
const PORT = process.env.PORT || 3000

// Middleware
app.use(cors({
  origin: process.env.FRONTEND_URL || 'http://localhost:5173',
  credentials: true,
}))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

// Routes
app.use('/api/auth', authRoutes)
app.use('/api/media', mediaRoutes)

// Health check
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok' })
})

// Error handling
app.use(errorHandler)

// 404 handler
app.use((req, res) => {
  res.status(404).json({ error: 'Not found' })
})

// Start server
app.listen(PORT, () => {
  console.log(\`Server running on port \${PORT}\`)
})
`);
console.log('Created src/server.js');

console.log('\\n✅ Backend structure created successfully!');
console.log('Next steps:');
console.log('  cd backend');
console.log('  npm install');
console.log('  cp .env.example .env');
console.log('  npm run dev');
