import { Request, Response } from 'express';
import { z } from 'zod';
import settingsService from '../services/settings.service';
import pool from '../config/database';
import logger from '../utils/logger';

const updateSchema = z.object({
  value: z.any(),
});

const externalLinkSchema = z.array(z.object({
  id: z.string().min(1),
  name: z.string().min(1).max(200),
  links: z.array(z.object({
    name: z.string().min(1).max(200),
    url: z.string().url().max(500),
  })),
}));

class SettingsController {
  async getAll(_req: Request, res: Response): Promise<void> {
    try {
      const settings = await settingsService.getAll();
      res.json({ success: true, data: settings });
    } catch (error) {
      logger.error('Failed to get settings', { error });
      res.status(500).json({ success: false, message: 'Failed to get settings' });
    }
  }

  async get(req: Request, res: Response): Promise<void> {
    try {
      const setting = await settingsService.get(req.params.key as string);
      if (!setting) {
        res.status(404).json({ success: false, message: 'Setting not found' });
        return;
      }
      res.json({ success: true, data: setting });
    } catch (error) {
      logger.error('Failed to get setting', { error });
      res.status(500).json({ success: false, message: 'Failed to get setting' });
    }
  }

  async update(req: Request, res: Response): Promise<void> {
    try {
      const { value } = updateSchema.parse(req.body);

      // Validate external_links specifically
      if ((req.params.key as string) === 'external_links') {
        externalLinkSchema.parse(value);
      }

      const setting = await settingsService.set(req.params.key as string, value, req.user!.id);
      res.json({ success: true, data: setting });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({ success: false, message: 'Invalid input', errors: error.issues });
        return;
      }
      logger.error('Failed to update setting', { error });
      res.status(500).json({ success: false, message: 'Failed to update setting' });
    }
  }
  async getUserPreferences(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user.id;
      const result = await pool.query('SELECT preferences FROM users WHERE id = $1', [userId]);
      const prefs = result.rows[0]?.preferences ?? {};
      res.json({ success: true, data: prefs });
    } catch (error) {
      logger.error('Failed to get user preferences', { error });
      res.status(500).json({ success: false, message: 'Failed to get user preferences' });
    }
  }

  async updateUserPreferences(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user.id;
      const preferences = req.body;

      // Basic validation — reject excessively large or non-object payloads
      if (typeof preferences !== 'object' || preferences === null || Array.isArray(preferences)) {
        res.status(400).json({ success: false, message: 'Preferences must be a JSON object' });
        return;
      }
      if (JSON.stringify(preferences).length > 10_000) {
        res.status(400).json({ success: false, message: 'Preferences payload too large' });
        return;
      }

      await pool.query(
        'UPDATE users SET preferences = $1 WHERE id = $2',
        [JSON.stringify(preferences), userId]
      );
      res.json({ success: true });
    } catch (error) {
      logger.error('Failed to update user preferences', { error });
      res.status(500).json({ success: false, message: 'Failed to update user preferences' });
    }
  }
}

export default new SettingsController();
