import { Router, Request, Response, NextFunction } from 'express';
import multer from 'multer';
import { cutsService } from './cuts.service';
import { createCutSchema, updateCutSchema, listCutsSchema } from './cuts.schemas';
import { validate } from '../../../middleware/validate';
import { authenticate } from '../../../middleware/auth.middleware';
import { requireRole } from '../../../middleware/rbac.middleware';
import { MAP_ROLES } from '../../../utils/roles';

const geojsonUpload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 10 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (file.originalname.endsWith('.geojson') || file.originalname.endsWith('.json') || file.mimetype === 'application/json' || file.mimetype === 'application/geo+json') {
      cb(null, true);
    } else {
      cb(new Error('Only .geojson or .json files are allowed'));
    }
  },
});

// --- Admin Router ---
const adminRouter = Router();
adminRouter.use(authenticate);
adminRouter.use(requireRole(...MAP_ROLES));

// GET /api/map/cuts — list paginated
adminRouter.get(
  '/',
  validate(listCutsSchema, 'query'),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const result = await cutsService.findAll(req.query as any);
      res.json(result);
    } catch (err) {
      next(err);
    }
  }
);

// GET /api/map/cuts/export-geojson — all cuts as FeatureCollection
adminRouter.get(
  '/export-geojson',
  async (_req: Request, res: Response, next: NextFunction) => {
    try {
      const collection = await cutsService.exportAllGeoJson();
      res.setHeader('Content-Type', 'application/geo+json');
      res.setHeader('Content-Disposition', 'attachment; filename=cuts.geojson');
      res.json(collection);
    } catch (err) {
      next(err);
    }
  }
);

// POST /api/map/cuts/import-geojson — upload + create cuts
adminRouter.post(
  '/import-geojson',
  geojsonUpload.single('file'),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      if (!req.file) {
        res.status(400).json({ error: { message: 'No file uploaded', code: 'NO_FILE' } });
        return;
      }
      const result = await cutsService.importGeoJson(req.file.buffer, req.user!.id);
      res.json(result);
    } catch (err) {
      next(err);
    }
  }
);

// GET /api/map/cuts/:id/export-geojson — single cut as Feature
adminRouter.get(
  '/:id/export-geojson',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const feature = await cutsService.exportSingleGeoJson(id);
      res.setHeader('Content-Type', 'application/geo+json');
      res.setHeader('Content-Disposition', `attachment; filename=cut-${id}.geojson`);
      res.json(feature);
    } catch (err) {
      next(err);
    }
  }
);

// GET /api/map/cuts/:id — single cut
adminRouter.get(
  '/:id',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const cut = await cutsService.findById(id);
      res.json(cut);
    } catch (err) {
      next(err);
    }
  }
);

// POST /api/map/cuts — create cut
adminRouter.post(
  '/',
  validate(createCutSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const cut = await cutsService.create(req.body, req.user!.id);
      res.status(201).json(cut);
    } catch (err) {
      next(err);
    }
  }
);

// PUT /api/map/cuts/:id — update cut
adminRouter.put(
  '/:id',
  validate(updateCutSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const cut = await cutsService.update(id, req.body);
      res.json(cut);
    } catch (err) {
      next(err);
    }
  }
);

// DELETE /api/map/cuts/:id — delete cut
adminRouter.delete(
  '/:id',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      await cutsService.delete(id);
      res.status(204).send();
    } catch (err) {
      next(err);
    }
  }
);

// GET /api/map/cuts/:id/locations — locations within cut
adminRouter.get(
  '/:id/locations',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const locations = await cutsService.getLocationsInCut(id);
      res.json(locations);
    } catch (err) {
      next(err);
    }
  }
);

// GET /api/map/cuts/:id/statistics — support level breakdown for cut
adminRouter.get(
  '/:id/statistics',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = req.params.id as string;
      const stats = await cutsService.getStatistics(id);
      res.json(stats);
    } catch (err) {
      next(err);
    }
  }
);

// --- Public Router ---
const publicRouter = Router();

// GET /api/map/cuts/public?limit=50 — public cuts for map display
publicRouter.get(
  '/public',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const limit = Math.min(parseInt(req.query.limit as string) || 50, 100);
      const cuts = await cutsService.getPublicCuts(limit);
      res.json(cuts);
    } catch (err) {
      next(err);
    }
  }
);

export { adminRouter as cutsAdminRouter, publicRouter as cutsPublicRouter };
