import { Response, Router } from 'express';
import {
  deletePluginEventDefinition,
  deletePluginRequirement,
  getPluginRequirementsSnapshot,
  PluginSupportError,
  upsertPluginEventDefinition,
  upsertPluginRequirement
} from '../services/plugin-support.service';
import { broadcastToServer } from '../websocket/broadcast';
import { getAuthenticatedUserId, requireAuth } from '../middleware/require-auth';

const router = Router();

function sendPluginSupportError(error: unknown, res: Response): void {
  if (error instanceof PluginSupportError) {
    res.status(error.status).json({ error: error.message, errorCode: error.code });
    return;
  }

  console.error('Unhandled plugin support error:', error);
  res.status(500).json({ error: 'Internal server error', errorCode: 'INTERNAL_ERROR' });
}

type AuthenticatedRequest = Parameters<typeof getAuthenticatedUserId>[0] & { body: { actorUserId?: unknown } };

function readOptionalActorUserId(req: AuthenticatedRequest, res: Response): string | null {
  let authenticatedUserId: string;

  try {
    authenticatedUserId = getAuthenticatedUserId(req);
  } catch {
    res.status(401).json({ error: 'Missing or invalid authorization token', errorCode: 'UNAUTHORIZED' });
    return null;
  }

  if (typeof req.body.actorUserId === 'string' && req.body.actorUserId.trim() && req.body.actorUserId !== authenticatedUserId) {
    res.status(400).json({
      error: 'actorUserId must match the authenticated user',
      errorCode: 'USER_ID_MISMATCH'
    });

    return null;
  }

  return authenticatedUserId;
}

async function broadcastRequirementsSnapshot(serverId: string): Promise<void> {
  const snapshot = await getPluginRequirementsSnapshot(serverId);

  broadcastToServer(serverId, {
    type: 'plugin_requirements_changed',
    serverId,
    snapshot
  });
}

router.get('/:serverId/plugins', async (req, res) => {
  try {
    res.json(await getPluginRequirementsSnapshot(req.params.serverId));
  } catch (error) {
    sendPluginSupportError(error, res);
  }
});

router.put('/:serverId/plugins/:pluginId/requirement', requireAuth, async (req, res) => {
  const { serverId, pluginId } = req.params;
  const actorUserId = readOptionalActorUserId(req, res);

  if (!actorUserId) {
    return;
  }

  try {
    const requirement = await upsertPluginRequirement({
      actorUserId,
      installUrl: req.body.installUrl,
      manifest: req.body.manifest,
      pluginId,
      reason: req.body.reason,
      serverId,
      sourceUrl: req.body.sourceUrl,
      status: req.body.status,
      versionRange: req.body.versionRange
    });

    await broadcastRequirementsSnapshot(serverId);
    res.json({ requirement });
  } catch (error) {
    sendPluginSupportError(error, res);
  }
});

router.delete('/:serverId/plugins/:pluginId/requirement', requireAuth, async (req, res) => {
  const { serverId, pluginId } = req.params;
  const actorUserId = readOptionalActorUserId(req, res);

  if (!actorUserId) {
    return;
  }

  try {
    await deletePluginRequirement({
      actorUserId,
      pluginId,
      serverId
    });

    await broadcastRequirementsSnapshot(serverId);
    res.json({ ok: true });
  } catch (error) {
    sendPluginSupportError(error, res);
  }
});

router.put('/:serverId/plugins/:pluginId/events/:eventName', requireAuth, async (req, res) => {
  const { serverId, pluginId, eventName } = req.params;
  const actorUserId = readOptionalActorUserId(req, res);

  if (!actorUserId) {
    return;
  }

  try {
    const eventDefinition = await upsertPluginEventDefinition({
      actorUserId,
      direction: req.body.direction,
      eventName,
      maxPayloadBytes: req.body.maxPayloadBytes,
      pluginId,
      rateLimitJson: req.body.rateLimitJson,
      schemaJson: req.body.schemaJson,
      scope: req.body.scope,
      serverId
    });

    await broadcastRequirementsSnapshot(serverId);
    res.json({ eventDefinition });
  } catch (error) {
    sendPluginSupportError(error, res);
  }
});

router.delete('/:serverId/plugins/:pluginId/events/:eventName', requireAuth, async (req, res) => {
  const { serverId, pluginId, eventName } = req.params;
  const actorUserId = readOptionalActorUserId(req, res);

  if (!actorUserId) {
    return;
  }

  try {
    await deletePluginEventDefinition({
      actorUserId,
      eventName,
      pluginId,
      serverId
    });

    await broadcastRequirementsSnapshot(serverId);
    res.json({ ok: true });
  } catch (error) {
    sendPluginSupportError(error, res);
  }
});

router.get('/:serverId/plugins/:pluginId/data', (_req, res) => {
  res.status(410).json({
    error: 'Plugin data persistence is disabled on the signal server',
    errorCode: 'PLUGIN_DATA_DISABLED'
  });
});

router.put('/:serverId/plugins/:pluginId/data/:key', (_req, res) => {
  res.status(410).json({
    error: 'Plugin data persistence is disabled on the signal server',
    errorCode: 'PLUGIN_DATA_DISABLED'
  });
});

router.delete('/:serverId/plugins/:pluginId/data/:key', (_req, res) => {
  res.status(410).json({
    error: 'Plugin data persistence is disabled on the signal server',
    errorCode: 'PLUGIN_DATA_DISABLED'
  });
});

export default router;
