import dotenv from "dotenv";
import express from "express";
import cors from "cors";
import session from "express-session";
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
import { v4 as uuidv4 } from "uuid";

// Load environment variables
dotenv.config();
import {
    authenticateUser,
    getUserByUsername,
    changeUserPassword,
} from "./auth.js";
import {
    getAllThemes,
    getActiveTheme,
    setActiveTheme,
    createCustomTheme,
    updateCustomTheme,
    deleteCustomTheme,
    exportTheme,
} from "./themes.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();
app.set("trust proxy", 1); // Trust the first proxy (Caddy) so secure cookies work behind HTTPS termination
const PORT = process.env.PORT || 3001;

// Paths
const POSTS_DIR = path.resolve(
    __dirname,
    process.env.POSTS_DIR || "../public/posts",
);
const INDEX_FILE = path.join(POSTS_DIR, "index.json");

// Middleware
app.use(
    cors({
        origin: [
            "http://localhost:5173",
            "https://goonblog.thevakhovske.eu.org",
        ],
        credentials: true, // Enable cookies
    }),
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Session configuration
app.use(
    session({
        secret:
            process.env.SESSION_SECRET ||
            "gooneral-wheelchair-secret-key-change-in-production",
        resave: false,
        saveUninitialized: false,
        name: "gooneral-session",
        cookie: {
            secure: true, // HTTPS required
            httpOnly: true,
            maxAge: 24 * 60 * 60 * 1000, // 24 hours
            sameSite: "lax", // Changed from 'strict' to 'lax'
        },
    }),
);

// Ensure posts directory exists
await fs.ensureDir(POSTS_DIR);

// Authentication middleware
function requireAuth(req, res, next) {
    if (req.session && req.session.user && req.session.user.role === "admin") {
        return next();
    }
    return res.status(401).json({ error: "Authentication required" });
}

// Check if user is authenticated
function isAuthenticated(req, res, next) {
    req.isAuthenticated = !!(req.session && req.session.user);
    req.user = req.session?.user || null;
    next();
}

// Helper function to generate index.json
async function generateIndex() {
    try {
        const files = await fs.readdir(POSTS_DIR);
        const mdFiles = files.filter((f) => f.endsWith(".md"));
        await fs.writeJSON(INDEX_FILE, mdFiles, { spaces: 2 });
        console.log(`Index updated: ${mdFiles.length} posts`);
        return mdFiles;
    } catch (error) {
        console.error("Error generating index:", error);
        throw error;
    }
}

// Helper function to parse post metadata
function parsePostMetadata(content) {
    const titleMatch = content.match(/title:\s*(.*)/);
    const descMatch = content.match(/desc:\s*(.*)/);
    const tagsMatch = content.match(/tags:\s*(.*)/);

    return {
        title: titleMatch ? titleMatch[1].trim() : "Untitled",
        description: descMatch ? descMatch[1].trim() : "",
        tags: tagsMatch ? tagsMatch[1].split(",").map((tag) => tag.trim()) : [],
    };
}

// Helper function to generate filename from title
function generateFilename(title) {
    // Create date-based filename similar to existing pattern
    const date = new Date();
    const dateStr = date.toISOString().slice(0, 10).replace(/-/g, "");
    const slug = title
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/^-|-$/g, "")
        .slice(0, 30);

    return slug ? `${dateStr}-${slug}.md` : `${dateStr}.md`;
}

// Authentication Routes

// POST /api/auth/login - Login
app.post('/api/auth/login', async (req, res) => {
  try {
    const { username, password } = req.body;
    
    if (!username || !password) {
      return res.status(400).json({ error: 'Username and password are required' });
    }
    
    const user = await authenticateUser(username, password);
    if (!user) {
      return res.status(401).json({ error: 'Invalid username or password' });
    }
    
    // Store user in session
    req.session.user = user;
    console.log('Login successful - Session ID:', req.sessionID);
    console.log('Login successful - Stored user:', req.session.user);
    
    // Manually save the session to ensure it's persisted
    req.session.save((err) => {
      if (err) {
        console.error('Session save error:', err);
        return res.status(500).json({ error: 'Failed to save session' });
      }
      
      console.log('Session saved successfully');
      res.json({ 
        success: true, 
        user: {
          username: user.username,
          role: user.role
        }
      });
    });
  } catch (error) {
    console.error('Login error:', error);
    res.status(500).json({ error: 'Login failed' });
  }
});

// POST /api/auth/logout - Logout
app.post('/api/auth/logout', (req, res) => {
  req.session.destroy((err) => {
    if (err) {
      return res.status(500).json({ error: 'Logout failed' });
    }
    res.clearCookie('gooneral-session'); // Use the same name as configured
    res.json({ success: true, message: 'Logged out successfully' });
  });
});

// GET /api/auth/me - Get current user
app.get('/api/auth/me', isAuthenticated, (req, res) => {
  console.log('Auth check - Session ID:', req.sessionID);
  console.log('Auth check - Session user:', req.session?.user);
  console.log('Auth check - Is authenticated:', req.isAuthenticated);
  
  if (req.isAuthenticated) {
    res.json({ 
      user: {
        username: req.user.username,
        role: req.user.role
      }
    });
  } else {
    res.json({ user: null });
  }
});

// POST /api/auth/change-password - Change password
app.post("/api/auth/change-password", requireAuth, async (req, res) => {
    try {
        const { currentPassword, newPassword } = req.body;

        if (!currentPassword || !newPassword) {
            return res.status(400).json({
                error: "Current password and new password are required",
            });
        }

        if (newPassword.length < 6) {
            return res.status(400).json({
                error: "New password must be at least 6 characters long",
            });
        }

        const result = await changeUserPassword(
            req.user.username,
            currentPassword,
            newPassword,
        );

        if (result.success) {
            res.json({ success: true, message: result.message });
        } else {
            res.status(400).json({ error: result.message });
        }
    } catch (error) {
        console.error("Change password error:", error);
        res.status(500).json({ error: "Failed to change password" });
    }
});

// API Routes

// GET /api/posts - Get all posts with metadata
app.get("/api/posts", async (req, res) => {
    try {
        const files = await generateIndex();
        const posts = [];

        for (const filename of files) {
            const filePath = path.join(POSTS_DIR, filename);
            const content = await fs.readFile(filePath, "utf8");
            const metadata = parsePostMetadata(content);
            const slug = filename.replace(".md", "");

            posts.push({
                slug,
                filename,
                ...metadata,
                content,
                createdAt: (await fs.stat(filePath)).birthtime,
                updatedAt: (await fs.stat(filePath)).mtime,
            });
        }

        // Sort by creation date, newest first
        posts.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));

        res.json(posts);
    } catch (error) {
        console.error("Error fetching posts:", error);
        res.status(500).json({ error: "Failed to fetch posts" });
    }
});

// GET /api/posts/:slug - Get specific post
app.get("/api/posts/:slug", async (req, res) => {
    try {
        const { slug } = req.params;
        const filename = `${slug}.md`;
        const filePath = path.join(POSTS_DIR, filename);

        if (!(await fs.pathExists(filePath))) {
            return res.status(404).json({ error: "Post not found" });
        }

        const content = await fs.readFile(filePath, "utf8");
        const metadata = parsePostMetadata(content);
        const stats = await fs.stat(filePath);

        res.json({
            slug,
            filename,
            ...metadata,
            content,
            createdAt: stats.birthtime,
            updatedAt: stats.mtime,
        });
    } catch (error) {
        console.error("Error fetching post:", error);
        res.status(500).json({ error: "Failed to fetch post" });
    }
});

// POST /api/posts - Create new post
app.post("/api/posts", requireAuth, async (req, res) => {
    try {
        const { title, description, content, tags } = req.body;

        if (!title || !content) {
            return res
                .status(400)
                .json({ error: "Title and content are required" });
        }

        // Generate filename
        const filename = generateFilename(title);
        const filePath = path.join(POSTS_DIR, filename);

        // Check if file already exists
        if (await fs.pathExists(filePath)) {
            return res
                .status(409)
                .json({ error: "Post with similar title already exists" });
        }

        // Format the post content
        let postContent = "";
        postContent += `title: ${title}\n`;
        if (description) postContent += `desc: ${description}\n`;
        if (tags && tags.length > 0)
            postContent += `tags: ${tags.join(", ")}\n`;
        postContent += "\n" + content;

        // Write the file
        await fs.writeFile(filePath, postContent, "utf8");

        // Update index
        await generateIndex();

        const slug = filename.replace(".md", "");
        const stats = await fs.stat(filePath);

        res.status(201).json({
            slug,
            filename,
            title,
            description: description || "",
            tags: tags || [],
            content: postContent,
            createdAt: stats.birthtime,
            updatedAt: stats.mtime,
        });
    } catch (error) {
        console.error("Error creating post:", error);
        res.status(500).json({ error: "Failed to create post" });
    }
});

// PUT /api/posts/:slug - Update existing post
app.put("/api/posts/:slug", requireAuth, async (req, res) => {
    try {
        const { slug } = req.params;
        const { title, description, content, tags } = req.body;

        const oldFilename = `${slug}.md`;
        const oldFilePath = path.join(POSTS_DIR, oldFilename);

        if (!(await fs.pathExists(oldFilePath))) {
            return res.status(404).json({ error: "Post not found" });
        }

        if (!title || !content) {
            return res
                .status(400)
                .json({ error: "Title and content are required" });
        }

        // Generate new filename if title changed
        const newFilename = generateFilename(title);
        const newFilePath = path.join(POSTS_DIR, newFilename);

        // Format the post content
        let postContent = "";
        postContent += `title: ${title}\n`;
        if (description) postContent += `desc: ${description}\n`;
        if (tags && tags.length > 0)
            postContent += `tags: ${tags.join(", ")}\n`;
        postContent += "\n" + content;

        // Write to new file
        await fs.writeFile(newFilePath, postContent, "utf8");

        // If filename changed, remove old file
        if (oldFilename !== newFilename) {
            await fs.remove(oldFilePath);
        }

        // Update index
        await generateIndex();

        const newSlug = newFilename.replace(".md", "");
        const stats = await fs.stat(newFilePath);

        res.json({
            slug: newSlug,
            filename: newFilename,
            title,
            description: description || "",
            tags: tags || [],
            content: postContent,
            createdAt: stats.birthtime,
            updatedAt: stats.mtime,
        });
    } catch (error) {
        console.error("Error updating post:", error);
        res.status(500).json({ error: "Failed to update post" });
    }
});

// DELETE /api/posts/:slug - Delete post
app.delete("/api/posts/:slug", requireAuth, async (req, res) => {
    try {
        const { slug } = req.params;
        const filename = `${slug}.md`;
        const filePath = path.join(POSTS_DIR, filename);

        if (!(await fs.pathExists(filePath))) {
            return res.status(404).json({ error: "Post not found" });
        }

        await fs.remove(filePath);
        await generateIndex();

        res.json({ message: "Post deleted successfully" });
    } catch (error) {
        console.error("Error deleting post:", error);
        res.status(500).json({ error: "Failed to delete post" });
    }
});

// Theme API Routes

// GET /api/themes - Get all themes
app.get("/api/themes", async (req, res) => {
    try {
        const themesData = await getAllThemes();
        res.json(themesData);
    } catch (error) {
        console.error("Error fetching themes:", error);
        res.status(500).json({ error: "Failed to fetch themes" });
    }
});

// GET /api/themes/active - Get active theme
app.get("/api/themes/active", async (req, res) => {
    try {
        const activeTheme = await getActiveTheme();
        res.json(activeTheme);
    } catch (error) {
        console.error("Error fetching active theme:", error);
        res.status(500).json({ error: "Failed to fetch active theme" });
    }
});

// PUT /api/themes/active - Set active theme
app.put("/api/themes/active", requireAuth, async (req, res) => {
    try {
        const { themeId } = req.body;

        if (!themeId) {
            return res.status(400).json({ error: "Theme ID is required" });
        }

        const activeTheme = await setActiveTheme(themeId);
        res.json({ success: true, theme: activeTheme });
    } catch (error) {
        console.error("Error setting active theme:", error);
        res.status(400).json({ error: error.message });
    }
});

// POST /api/themes - Create custom theme
app.post("/api/themes", requireAuth, async (req, res) => {
    try {
        const themeData = req.body;
        const newTheme = await createCustomTheme(themeData);
        res.status(201).json(newTheme);
    } catch (error) {
        console.error("Error creating theme:", error);
        res.status(400).json({ error: error.message });
    }
});

// PUT /api/themes/:themeId - Update custom theme
app.put("/api/themes/:themeId", requireAuth, async (req, res) => {
    try {
        const { themeId } = req.params;
        const themeData = req.body;

        const updatedTheme = await updateCustomTheme(themeId, themeData);
        res.json(updatedTheme);
    } catch (error) {
        console.error("Error updating theme:", error);
        res.status(400).json({ error: error.message });
    }
});

// DELETE /api/themes/:themeId - Delete custom theme
app.delete("/api/themes/:themeId", requireAuth, async (req, res) => {
    try {
        const { themeId } = req.params;
        await deleteCustomTheme(themeId);
        res.json({ success: true, message: "Theme deleted successfully" });
    } catch (error) {
        console.error("Error deleting theme:", error);
        res.status(400).json({ error: error.message });
    }
});

// GET /api/themes/:themeId/export - Export theme
app.get("/api/themes/:themeId/export", requireAuth, async (req, res) => {
    try {
        const { themeId } = req.params;
        const themeData = await exportTheme(themeId);

        res.setHeader("Content-Type", "application/json");
        res.setHeader(
            "Content-Disposition",
            `attachment; filename="theme-${themeId}.json"`,
        );
        res.json(themeData);
    } catch (error) {
        console.error("Error exporting theme:", error);
        res.status(400).json({ error: error.message });
    }
});

// Health check endpoint
app.get("/api/health", (req, res) => {
    res.json({ status: "OK", timestamp: new Date().toISOString() });
});

// Generate initial index on startup
await generateIndex();

app.listen(PORT, () => {
    console.log(`🚀 Backend server running on http://localhost:${PORT}`);
    console.log(`📁 Posts directory: ${POSTS_DIR}`);
});
