import { Router } from 'express';
import { validate } from '../../middleware/validate';
import { authenticate } from '../../middleware/auth.middleware';
import { requireRole } from '../../middleware/rbac.middleware';
import {
  docsCommentAnonRateLimit,
  docsCommentAuthRateLimit,
  docsCommentFetchRateLimit,
} from '../../middleware/rate-limit';
import { docsCommentsService } from './docs-comments.service';
import { giteaClient } from '../../services/gitea.client';
import {
  getCommentsSchema,
  postAnonymousCommentSchema,
  postAuthenticatedCommentSchema,
  oauthExchangeSchema,
  moderateCommentSchema,
  moderationQuerySchema,
} from './docs-comments.schemas';
import { env } from '../../config/env';
import { CONTENT_ROLES } from '../../utils/roles';

// --- Public Router (CORS override for docs origin) ---
export const docsCommentsPublicRouter = Router();

// Per-route CORS: MkDocs runs on a different origin (root domain vs API subdomain)
docsCommentsPublicRouter.use((_req, res, next) => {
  // Allow both the docs origin and the admin app origin
  const allowedOrigins = [
    env.ADMIN_URL,
    `https://${env.DOMAIN}`,
    `https://docs.${env.DOMAIN}`,
    `http://localhost:${env.MKDOCS_PORT}`,
  ];
  const origin = _req.headers.origin;
  if (origin && allowedOrigins.includes(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }
  res.setHeader('Vary', 'Origin');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Gitea-Token');
  next();
});

// Handle preflight for all public routes
docsCommentsPublicRouter.options('*', (_req, res) => {
  res.sendStatus(204);
});

// GET /api/docs-comments/comments?pagePath=...&page=1
docsCommentsPublicRouter.get(
  '/comments',
  docsCommentFetchRateLimit,
  validate(getCommentsSchema, 'query'),
  async (req, res, next) => {
    try {
      if (!(await giteaClient.isEnabled())) {
        res.status(404).json({ error: 'Comments are not enabled' });
        return;
      }
      const { pagePath, page } = req.query as { pagePath: string; page: string };
      const result = await docsCommentsService.getPageComments(pagePath, Number(page) || 1);
      res.json(result);
    } catch (err) {
      next(err);
    }
  },
);

// POST /api/docs-comments/comments/anonymous
docsCommentsPublicRouter.post(
  '/comments/anonymous',
  docsCommentAnonRateLimit,
  validate(postAnonymousCommentSchema),
  async (req, res, next) => {
    try {
      if (!(await giteaClient.isEnabled())) {
        res.status(404).json({ error: 'Comments are not enabled' });
        return;
      }

      // Honeypot check — if filled, silently accept but don't store
      if (req.body.website) {
        res.json({ id: 'ignored', status: 'pending' });
        return;
      }

      const result = await docsCommentsService.postAnonymousComment({
        pagePath: req.body.pagePath,
        authorName: req.body.authorName,
        authorEmail: req.body.authorEmail,
        body: req.body.body,
      });

      res.status(201).json(result);
    } catch (err) {
      next(err);
    }
  },
);

// POST /api/docs-comments/comments/authenticated
docsCommentsPublicRouter.post(
  '/comments/authenticated',
  docsCommentAuthRateLimit,
  validate(postAuthenticatedCommentSchema),
  async (req, res, next) => {
    try {
      if (!(await giteaClient.isEnabled())) {
        res.status(404).json({ error: 'Comments are not enabled' });
        return;
      }

      const userToken = req.headers['x-gitea-token'] as string;
      if (!userToken) {
        res.status(401).json({ error: 'Missing X-Gitea-Token header' });
        return;
      }

      const result = await docsCommentsService.postAuthenticatedComment({
        pagePath: req.body.pagePath,
        body: req.body.body,
        userToken,
      });

      res.status(201).json(result);
    } catch (err) {
      next(err);
    }
  },
);

// POST /api/docs-comments/oauth/exchange
docsCommentsPublicRouter.post(
  '/oauth/exchange',
  docsCommentAuthRateLimit,
  validate(oauthExchangeSchema),
  async (req, res, next) => {
    try {
      if (!(await giteaClient.isOAuthEnabled())) {
        res.status(404).json({ error: 'OAuth is not configured' });
        return;
      }

      const tokenResponse = await giteaClient.exchangeOAuthCode(
        req.body.code,
        req.body.redirectUri,
      );

      if (!tokenResponse) {
        res.status(400).json({ error: 'OAuth code exchange failed' });
        return;
      }

      // Also fetch user info so the widget can display name/avatar
      const user = await giteaClient.getAuthenticatedUser(tokenResponse.access_token);

      res.json({
        accessToken: tokenResponse.access_token,
        user: user
          ? {
              login: user.login,
              name: user.full_name || user.login,
              avatarUrl: user.avatar_url,
            }
          : null,
      });
    } catch (err) {
      next(err);
    }
  },
);

// GET /api/docs-comments/oauth/config — public config for the widget
docsCommentsPublicRouter.get('/oauth/config', async (_req, res) => {
  const enabled = await giteaClient.isEnabled();
  if (!enabled) {
    res.status(404).json({ error: 'Comments are not enabled' });
    return;
  }

  const config = await giteaClient.getConfig();
  const oauthEnabled = await giteaClient.isOAuthEnabled();

  res.json({
    enabled: true,
    oauthEnabled,
    clientId: config.oauthClientId || null,
    authorizeUrl: oauthEnabled ? giteaClient.getAuthorizeUrl() : null,
  });
});

// --- Admin Router (auth required) ---
export const docsCommentsAdminRouter = Router();
docsCommentsAdminRouter.use(authenticate);
docsCommentsAdminRouter.use(requireRole(...CONTENT_ROLES));

// GET /api/docs-comments/moderation?status=PENDING&page=1
docsCommentsAdminRouter.get(
  '/moderation',
  validate(moderationQuerySchema, 'query'),
  async (req, res, next) => {
    try {
      const { status, page, pageSize } = req.query as {
        status?: string;
        page: string;
        pageSize: string;
      };

      const result = await docsCommentsService.getModerationQueue({
        status: status as any,
        page: Number(page) || 1,
        pageSize: Number(pageSize) || 20,
      });

      res.json(result);
    } catch (err) {
      next(err);
    }
  },
);

// POST /api/docs-comments/moderation/:id — approve or reject
docsCommentsAdminRouter.post(
  '/moderation/:id',
  validate(moderateCommentSchema),
  async (req, res, next) => {
    try {
      const id = req.params.id as string;
      const { action } = req.body;
      const reviewedBy = req.user?.email || 'unknown';

      const result = await docsCommentsService.moderateComment(id, action, reviewedBy);
      res.json(result);
    } catch (err) {
      next(err);
    }
  },
);

// POST /api/docs-comments/setup — create repo + labels
docsCommentsAdminRouter.post('/setup', async (_req, res, next) => {
  try {
    if (!(await giteaClient.isEnabled())) {
      res.status(400).json({ error: 'Gitea comments are not configured. Enable comments and set API token + repo owner in Settings > Web > Comments.' });
      return;
    }

    const result = await docsCommentsService.setup();
    res.json(result);
  } catch (err) {
    next(err);
  }
});

// GET /api/docs-comments/stats
docsCommentsAdminRouter.get('/stats', async (_req, res, next) => {
  try {
    const stats = await docsCommentsService.getStats();
    res.json(stats);
  } catch (err) {
    next(err);
  }
});
