import { Router } from 'express';
import { inspectUpload, upload } from '../middleware/upload.js';
import { config } from '../config.js';
import {
  listRoutes, getRoute, getRouteGpxFile, createRoute, updateRoute, appendRoute,
  listPois, getPoi, createPoi, updatePoi, deletePoi, softDeleteRoute, restoreRoute
} from '../services/routes-service.js';
import {
  listPictures, getPicture, getPictureFile, createPicture, updatePicture, deletePicture,
  getAudio, getAudioFile, createAudio, updateAudio, deleteAudio
} from '../services/media-service.js';

const numberOrUndefined = value => {
  if (value == null || value === '') return undefined;
  const parsed = Number.parseFloat(value);
  return Number.isFinite(parsed) ? parsed : undefined;
};

function sendFileResource(res, file, contentType = null) {
  if (contentType) res.type(contentType);
  res.setHeader('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(file.filename)}`);
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate');
  return res.sendFile(file.absolutePath, {
    acceptRanges: true,
    cacheControl: true,
    immutable: false,
    maxAge: 0
  });
}

export function createApiRouter(db) {
  const api = Router();

  api.use((req, res, next) => {
    res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');
    next();
  });

  api.get('/health', (req, res) => {
    const sqliteVersion = db.prepare('SELECT sqlite_version() AS version').get().version;
    res.json({
      ok: true,
      service: 'wegwichtel',
      socket: `${config.host}:${config.port}`,
      sqliteVersion,
      timestamp: new Date().toISOString()
    });
  });

  api.get('/routes', (req, res) => {
    res.json({ routes: listRoutes(db, {
      lat: numberOrUndefined(req.query.lat),
      lon: numberOrUndefined(req.query.lon),
      radiusKm: numberOrUndefined(req.query.radiusKm),
      includeDeleted: req.query.includeDeleted === 'true'
    }) });
  });

  api.get('/routes/:id', (req, res) => {
    res.json(getRoute(db, Number(req.params.id), req.query.includeDeleted === 'true'));
  });

  api.get('/routes/:id/gpx', (req, res) => {
    sendFileResource(res, getRouteGpxFile(db, Number(req.params.id)), 'application/gpx+xml');
  });

  api.get('/routes/:id/pois', (req, res) => {
    getRoute(db, Number(req.params.id));
    res.json({ pois: listPois(db, Number(req.params.id)) });
  });

  api.get('/routes/:routeId/pois/:poiId', (req, res) => {
    res.json(getPoi(db, Number(req.params.routeId), Number(req.params.poiId)));
  });

  api.post('/routes', upload.single('gpx'), inspectUpload('gpx', 'gpx'), (req, res) => {
    const route = createRoute(db, req.body, req.file);
    res.status(201).location(`/api/routes/${route.id}`).json(route);
  });

  api.put('/routes/:id', upload.single('gpx'), inspectUpload('gpx', 'gpx'), (req, res) => {
    res.json(updateRoute(db, Number(req.params.id), req.body, req.file));
  });

  api.post('/routes/:id/append', upload.single('gpx'), inspectUpload('gpx', 'gpx'), (req, res) => {
    res.json(appendRoute(db, Number(req.params.id), req.file));
  });

  api.post('/routes/:id/pois', upload.none(), (req, res) => {
    const poi = createPoi(db, Number(req.params.id), req.body);
    res.status(201)
      .location(`/api/routes/${req.params.id}/pois/${poi.id}`)
      .json(poi);
  });

  api.put('/routes/:routeId/pois/:poiId', upload.none(), (req, res) => {
    res.json(updatePoi(
      db,
      Number(req.params.routeId),
      Number(req.params.poiId),
      req.body
    ));
  });

  api.delete('/routes/:routeId/pois/:poiId', (req, res) => {
    res.json(deletePoi(db, Number(req.params.routeId), Number(req.params.poiId)));
  });

  api.get('/routes/:routeId/pois/:poiId/pictures', (req, res) => {
    res.json({ pictures: listPictures(db, Number(req.params.routeId), Number(req.params.poiId)) });
  });

  api.get('/routes/:routeId/pois/:poiId/pictures/:pictureId', (req, res) => {
    const routeId = Number(req.params.routeId);
    const poiId = Number(req.params.poiId);
    const pictureId = Number(req.params.pictureId);
    if (req.query.metadata === 'true') {
      res.json(getPicture(db, routeId, poiId, pictureId));
      return;
    }
    sendFileResource(res, getPictureFile(db, routeId, poiId, pictureId));
  });

  api.post('/routes/:routeId/pois/:poiId/pictures', upload.single('picture'), inspectUpload('picture', 'picture', { allowJson: true }), (req, res) => {
    const routeId = Number(req.params.routeId);
    const poiId = Number(req.params.poiId);
    const picture = createPicture(db, routeId, poiId, req.body, req.file);
    res.status(201)
      .location(`/api/routes/${routeId}/pois/${poiId}/pictures/${picture.id}`)
      .json(picture);
  });

  api.put('/routes/:routeId/pois/:poiId/pictures/:pictureId', upload.single('picture'), inspectUpload('picture', 'picture', { allowJson: true }), (req, res) => {
    res.json(updatePicture(
      db,
      Number(req.params.routeId),
      Number(req.params.poiId),
      Number(req.params.pictureId),
      req.body,
      req.file
    ));
  });

  api.delete('/routes/:routeId/pois/:poiId/pictures/:pictureId', (req, res) => {
    res.json(deletePicture(
      db,
      Number(req.params.routeId),
      Number(req.params.poiId),
      Number(req.params.pictureId)
    ));
  });

  api.get('/routes/:routeId/pois/:poiId/audio', (req, res) => {
    const routeId = Number(req.params.routeId);
    const poiId = Number(req.params.poiId);
    if (req.query.metadata === 'true') {
      res.json(getAudio(db, routeId, poiId));
      return;
    }
    sendFileResource(res, getAudioFile(db, routeId, poiId));
  });

  api.post('/routes/:routeId/pois/:poiId/audio', upload.single('audio'), inspectUpload('audio', 'audio', { allowJson: true }), (req, res) => {
    const routeId = Number(req.params.routeId);
    const poiId = Number(req.params.poiId);
    const audio = createAudio(db, routeId, poiId, req.file);
    res.status(201)
      .location(`/api/routes/${routeId}/pois/${poiId}/audio`)
      .json(audio);
  });

  api.put('/routes/:routeId/pois/:poiId/audio', upload.single('audio'), inspectUpload('audio', 'audio', { allowJson: true }), (req, res) => {
    res.json(updateAudio(db, Number(req.params.routeId), Number(req.params.poiId), req.file));
  });

  api.delete('/routes/:routeId/pois/:poiId/audio', (req, res) => {
    res.json(deleteAudio(db, Number(req.params.routeId), Number(req.params.poiId)));
  });

  api.delete('/routes/:id', (req, res) => {
    res.json({ route: softDeleteRoute(db, Number(req.params.id)), softDeleted: true });
  });

  api.post('/routes/:id/restore', (req, res) => {
    res.json({ route: restoreRoute(db, Number(req.params.id)), restored: true });
  });

  return api;
}
