import { Request, Response } from 'express';
import bestellungService from '../services/bestellung.service';
import { permissionService } from '../services/permission.service';
import logger from '../utils/logger';
import fs from 'fs';

// Helper to safely extract a route param as string
const param = (req: Request, key: string): string => req.params[key] as string;

class BestellungController {
  // ---------------------------------------------------------------------------
  // Members
  // ---------------------------------------------------------------------------

  async listMembers(_req: Request, res: Response): Promise<void> {
    try {
      const members = await bestellungService.getAllMembers();
      res.status(200).json({ success: true, data: members });
    } catch (error) {
      logger.error('BestellungController.listMembers error', { error });
      res.status(500).json({ success: false, message: 'Mitglieder konnten nicht geladen werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Catalog (shared ausruestung_artikel)
  // ---------------------------------------------------------------------------

  async listKatalogItems(req: Request, res: Response): Promise<void> {
    try {
      const search = req.query.search as string | undefined;
      const kategorie = req.query.kategorie as string | undefined;
      const items = await bestellungService.getKatalogItems({ search, kategorie });
      res.status(200).json({ success: true, data: items });
    } catch (error) {
      logger.error('BestellungController.listKatalogItems error', { error });
      res.status(500).json({ success: false, message: 'Katalogartikel konnten nicht geladen werden' });
    }
  }

  async getKatalogItem(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'itemId'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const item = await bestellungService.getKatalogItem(id);
      if (!item) {
        res.status(404).json({ success: false, message: 'Katalogartikel nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: item });
    } catch (error) {
      logger.error('BestellungController.getKatalogItem error', { error });
      res.status(500).json({ success: false, message: 'Katalogartikel konnte nicht geladen werden' });
    }
  }

  async listKatalogKategorien(_req: Request, res: Response): Promise<void> {
    try {
      const kategorien = await bestellungService.getKatalogKategorien();
      res.status(200).json({ success: true, data: kategorien });
    } catch (error) {
      logger.error('BestellungController.listKatalogKategorien error', { error });
      res.status(500).json({ success: false, message: 'Kategorien konnten nicht geladen werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Vendors
  // ---------------------------------------------------------------------------

  async listVendors(_req: Request, res: Response): Promise<void> {
    try {
      const vendors = await bestellungService.getVendors();
      res.status(200).json({ success: true, data: vendors });
    } catch (error) {
      logger.error('BestellungController.listVendors error', { error });
      res.status(500).json({ success: false, message: 'Lieferanten konnten nicht geladen werden' });
    }
  }

  async getVendor(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const vendor = await bestellungService.getVendorById(id);
      if (!vendor) {
        res.status(404).json({ success: false, message: 'Lieferant nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: vendor });
    } catch (error) {
      logger.error('BestellungController.getVendor error', { error });
      res.status(500).json({ success: false, message: 'Lieferant konnte nicht geladen werden' });
    }
  }

  async getVendorOrders(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const orders = await bestellungService.getOrders({ lieferant_id: id });
      res.status(200).json({ success: true, data: orders });
    } catch (error) {
      logger.error('BestellungController.getVendorOrders error', { error });
      res.status(500).json({ success: false, message: 'Bestellungen konnten nicht geladen werden' });
    }
  }

  async createVendor(req: Request, res: Response): Promise<void> {
    const { name } = req.body;
    if (!name || typeof name !== 'string' || name.trim().length === 0) {
      res.status(400).json({ success: false, message: 'Name ist erforderlich' });
      return;
    }
    try {
      const vendor = await bestellungService.createVendor(req.body, req.user!.id);
      res.status(201).json({ success: true, data: vendor });
    } catch (error) {
      logger.error('BestellungController.createVendor error', { error });
      res.status(500).json({ success: false, message: 'Lieferant konnte nicht erstellt werden' });
    }
  }

  async updateVendor(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const vendor = await bestellungService.updateVendor(id, req.body, req.user!.id);
      if (!vendor) {
        res.status(404).json({ success: false, message: 'Lieferant nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: vendor });
    } catch (error) {
      logger.error('BestellungController.updateVendor error', { error });
      res.status(500).json({ success: false, message: 'Lieferant konnte nicht aktualisiert werden' });
    }
  }

  async deleteVendor(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const deleted = await bestellungService.deleteVendor(id);
      if (!deleted) {
        res.status(404).json({ success: false, message: 'Lieferant nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, message: 'Lieferant gelöscht' });
    } catch (error) {
      logger.error('BestellungController.deleteVendor error', { error });
      res.status(500).json({ success: false, message: 'Lieferant konnte nicht gelöscht werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Orders
  // ---------------------------------------------------------------------------

  async listOrders(req: Request, res: Response): Promise<void> {
    try {
      const filters: { status?: string; lieferant_id?: number; besteller_id?: string } = {};
      if (req.query.status) filters.status = req.query.status as string;
      if (req.query.lieferant_id) filters.lieferant_id = parseInt(req.query.lieferant_id as string, 10);
      if (req.query.besteller_id) filters.besteller_id = req.query.besteller_id as string;

      const orders = await bestellungService.getOrders(filters);
      res.status(200).json({ success: true, data: orders });
    } catch (error) {
      logger.error('BestellungController.listOrders error', { error });
      res.status(500).json({ success: false, message: 'Bestellungen konnten nicht geladen werden' });
    }
  }

  async getOrder(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const order = await bestellungService.getOrderById(id);
      if (!order) {
        res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: order });
    } catch (error) {
      logger.error('BestellungController.getOrder error', { error });
      res.status(500).json({ success: false, message: 'Bestellung konnte nicht geladen werden' });
    }
  }

  async createOrder(req: Request, res: Response): Promise<void> {
    const { bezeichnung, lieferant_id, budget, besteller_id, positionen, mitglied_id } = req.body;
    if (!bezeichnung || typeof bezeichnung !== 'string' || bezeichnung.trim().length === 0) {
      res.status(400).json({ success: false, message: 'Bezeichnung ist erforderlich' });
      return;
    }
    if (lieferant_id != null && (!Number.isInteger(lieferant_id) || lieferant_id <= 0)) {
      res.status(400).json({ success: false, message: 'Ungültige Lieferanten-ID' });
      return;
    }
    if (budget != null && (typeof budget !== 'number' || budget < 0)) {
      res.status(400).json({ success: false, message: 'Budget muss eine positive Zahl sein' });
      return;
    }
    if (besteller_id != null && besteller_id !== '' && (typeof besteller_id !== 'string' || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(besteller_id))) {
      res.status(400).json({ success: false, message: 'Ungültige Besteller-ID' });
      return;
    }
    if (mitglied_id != null && mitglied_id !== '' && (typeof mitglied_id !== 'string' || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(mitglied_id))) {
      res.status(400).json({ success: false, message: 'Ungültige Mitglied-ID' });
      return;
    }
    if (positionen != null && !Array.isArray(positionen)) {
      res.status(400).json({ success: false, message: 'Positionen muss ein Array sein' });
      return;
    }
    try {
      const order = await bestellungService.createOrder(req.body, req.user!.id);
      res.status(201).json({ success: true, data: order });
    } catch (error) {
      logger.error('BestellungController.createOrder error', { error });
      res.status(500).json({ success: false, message: error instanceof Error ? error.message : 'Bestellung konnte nicht erstellt werden' });
    }
  }

  async updateOrder(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const order = await bestellungService.updateOrder(id, req.body, req.user!.id);
      if (!order) {
        res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: order });
    } catch (error) {
      logger.error('BestellungController.updateOrder error', { error });
      res.status(500).json({ success: false, message: 'Bestellung konnte nicht aktualisiert werden' });
    }
  }

  async deleteOrder(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const deleted = await bestellungService.deleteOrder(id, req.user!.id);
      if (!deleted) {
        res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, message: 'Bestellung gelöscht' });
    } catch (error) {
      logger.error('BestellungController.deleteOrder error', { error });
      res.status(500).json({ success: false, message: 'Bestellung konnte nicht gelöscht werden' });
    }
  }

  async updateStatus(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    const { status, force } = req.body;
    if (!status || typeof status !== 'string') {
      res.status(400).json({ success: false, message: 'Status ist erforderlich' });
      return;
    }
    try {
      // For force override, require manage_orders
      if (force) {
        const canManage = permissionService.hasPermission(req.user!.groups || [], 'bestellungen:manage_orders');
        if (!canManage) {
          res.status(403).json({ success: false, message: 'Keine Berechtigung für manuelle Statusänderung' });
          return;
        }
      }

      // For approval/rejection transitions, require bestellungen:approve
      if (status === 'bereit_zur_bestellung' || status === 'entwurf') {
        // Check if this is an approval/rejection (from wartet_auf_genehmigung)
        const currentOrder = await bestellungService.getOrderById(id);
        if (!currentOrder) {
          res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
          return;
        }
        const currentStatus = currentOrder.bestellung.status;
        if (currentStatus === 'wartet_auf_genehmigung') {
          const canApprove = permissionService.hasPermission(req.user!.groups || [], 'bestellungen:approve');
          if (!canApprove) {
            res.status(403).json({ success: false, message: 'Keine Berechtigung zur Genehmigung/Ablehnung von Bestellungen' });
            return;
          }
        }
      }

      const order = await bestellungService.updateOrderStatus(id, status, req.user!.id, !!force, req.user!.id);
      if (!order) {
        res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: order });
    } catch (error: any) {
      if (error.message?.includes('Ungültiger Statusübergang')) {
        res.status(400).json({ success: false, message: error.message });
        return;
      }
      logger.error('BestellungController.updateStatus error', { error });
      res.status(500).json({ success: false, message: 'Status konnte nicht aktualisiert werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Line Items
  // ---------------------------------------------------------------------------

  async addLineItem(req: Request, res: Response): Promise<void> {
    const bestellungId = parseInt(param(req, 'id'), 10);
    if (isNaN(bestellungId)) {
      res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
      return;
    }
    const { bezeichnung, menge } = req.body;
    if (!bezeichnung || typeof bezeichnung !== 'string' || bezeichnung.trim().length === 0) {
      res.status(400).json({ success: false, message: 'Bezeichnung ist erforderlich' });
      return;
    }
    if (menge === undefined || menge === null || menge <= 0) {
      res.status(400).json({ success: false, message: 'Menge muss größer als 0 sein' });
      return;
    }
    try {
      const item = await bestellungService.addLineItem(bestellungId, req.body, req.user!.id);
      res.status(201).json({ success: true, data: item });
    } catch (error) {
      logger.error('BestellungController.addLineItem error', { error });
      res.status(500).json({ success: false, message: 'Position konnte nicht hinzugefügt werden' });
    }
  }

  async updateLineItem(req: Request, res: Response): Promise<void> {
    const itemId = parseInt(param(req, 'itemId'), 10);
    if (isNaN(itemId)) {
      res.status(400).json({ success: false, message: 'Ungültige Position-ID' });
      return;
    }
    try {
      const item = await bestellungService.updateLineItem(itemId, req.body, req.user!.id);
      if (!item) {
        res.status(404).json({ success: false, message: 'Position nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: item });
    } catch (error) {
      logger.error('BestellungController.updateLineItem error', { error });
      res.status(500).json({ success: false, message: 'Position konnte nicht aktualisiert werden' });
    }
  }

  async deleteLineItem(req: Request, res: Response): Promise<void> {
    const itemId = parseInt(param(req, 'itemId'), 10);
    if (isNaN(itemId)) {
      res.status(400).json({ success: false, message: 'Ungültige Position-ID' });
      return;
    }
    try {
      const deleted = await bestellungService.deleteLineItem(itemId, req.user!.id);
      if (!deleted) {
        res.status(404).json({ success: false, message: 'Position nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, message: 'Position gelöscht' });
    } catch (error) {
      logger.error('BestellungController.deleteLineItem error', { error });
      res.status(500).json({ success: false, message: 'Position konnte nicht gelöscht werden' });
    }
  }

  async updateReceivedQuantity(req: Request, res: Response): Promise<void> {
    const itemId = parseInt(param(req, 'itemId'), 10);
    if (isNaN(itemId)) {
      res.status(400).json({ success: false, message: 'Ungültige Position-ID' });
      return;
    }
    const { menge } = req.body;
    if (menge === undefined || menge === null || menge < 0) {
      res.status(400).json({ success: false, message: 'Erhaltene Menge muss >= 0 sein' });
      return;
    }
    try {
      const item = await bestellungService.updateReceivedQuantity(itemId, menge, req.user!.id);
      if (!item) {
        res.status(404).json({ success: false, message: 'Position nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: item });
    } catch (error: any) {
      if (error.statusCode === 400) {
        res.status(400).json({ success: false, message: error.message });
        return;
      }
      logger.error('BestellungController.updateReceivedQuantity error', { error });
      res.status(500).json({ success: false, message: 'Liefermenge konnte nicht aktualisiert werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Files
  // ---------------------------------------------------------------------------

  async uploadFile(req: Request, res: Response): Promise<void> {
    const bestellungId = parseInt(param(req, 'id'), 10);
    if (isNaN(bestellungId)) {
      res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
      return;
    }
    const file = (req as any).file;
    if (!file) {
      res.status(400).json({ success: false, message: 'Keine Datei hochgeladen' });
      return;
    }
    try {
      const fileRecord = await bestellungService.addFile(bestellungId, {
        dateiname: file.originalname,
        dateipfad: file.path,
        dateityp: file.mimetype,
        dateigroesse: file.size,
      }, req.user!.id);
      res.status(201).json({ success: true, data: fileRecord });
    } catch (error) {
      logger.error('BestellungController.uploadFile error', { error });
      res.status(500).json({ success: false, message: 'Datei konnte nicht hochgeladen werden' });
    }
  }

  async deleteFile(req: Request, res: Response): Promise<void> {
    const fileId = parseInt(param(req, 'fileId'), 10);
    if (isNaN(fileId)) {
      res.status(400).json({ success: false, message: 'Ungültige Datei-ID' });
      return;
    }
    try {
      const result = await bestellungService.deleteFile(fileId, req.user!.id);
      if (!result) {
        res.status(404).json({ success: false, message: 'Datei nicht gefunden' });
        return;
      }
      // Remove from disk
      try {
        if (result.dateipfad && fs.existsSync(result.dateipfad)) {
          fs.unlinkSync(result.dateipfad);
        }
      } catch (err) {
        logger.warn('Failed to delete file from disk', { path: result.dateipfad, error: err });
      }
      res.status(200).json({ success: true, message: 'Datei gelöscht' });
    } catch (error) {
      logger.error('BestellungController.deleteFile error', { error });
      res.status(500).json({ success: false, message: 'Datei konnte nicht gelöscht werden' });
    }
  }

  async listFiles(req: Request, res: Response): Promise<void> {
    const bestellungId = parseInt(param(req, 'id'), 10);
    if (isNaN(bestellungId)) {
      res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
      return;
    }
    try {
      const files = await bestellungService.getFilesByOrder(bestellungId);
      res.status(200).json({ success: true, data: files });
    } catch (error) {
      logger.error('BestellungController.listFiles error', { error });
      res.status(500).json({ success: false, message: 'Dateien konnten nicht geladen werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Reminders
  // ---------------------------------------------------------------------------

  async addReminder(req: Request, res: Response): Promise<void> {
    const bestellungId = parseInt(param(req, 'id'), 10);
    if (isNaN(bestellungId)) {
      res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
      return;
    }
    const { faellig_am } = req.body;
    if (!faellig_am) {
      res.status(400).json({ success: false, message: 'Fälligkeitsdatum ist erforderlich' });
      return;
    }
    try {
      const reminder = await bestellungService.addReminder(bestellungId, req.body, req.user!.id);
      res.status(201).json({ success: true, data: reminder });
    } catch (error) {
      logger.error('BestellungController.addReminder error', { error });
      res.status(500).json({ success: false, message: 'Erinnerung konnte nicht erstellt werden' });
    }
  }

  async markReminderDone(req: Request, res: Response): Promise<void> {
    const remId = parseInt(param(req, 'remId'), 10);
    if (isNaN(remId)) {
      res.status(400).json({ success: false, message: 'Ungültige Erinnerungs-ID' });
      return;
    }
    try {
      const reminder = await bestellungService.markReminderDone(remId, req.user!.id);
      if (!reminder) {
        res.status(404).json({ success: false, message: 'Erinnerung nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: reminder });
    } catch (error) {
      logger.error('BestellungController.markReminderDone error', { error });
      res.status(500).json({ success: false, message: 'Erinnerung konnte nicht als erledigt markiert werden' });
    }
  }

  async deleteReminder(req: Request, res: Response): Promise<void> {
    const remId = parseInt(param(req, 'remId'), 10);
    if (isNaN(remId)) {
      res.status(400).json({ success: false, message: 'Ungültige Erinnerungs-ID' });
      return;
    }
    try {
      const deleted = await bestellungService.deleteReminder(remId);
      if (!deleted) {
        res.status(404).json({ success: false, message: 'Erinnerung nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, message: 'Erinnerung gelöscht' });
    } catch (error) {
      logger.error('BestellungController.deleteReminder error', { error });
      res.status(500).json({ success: false, message: 'Erinnerung konnte nicht gelöscht werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // History
  // ---------------------------------------------------------------------------

  async getHistory(req: Request, res: Response): Promise<void> {
    const bestellungId = parseInt(param(req, 'id'), 10);
    if (isNaN(bestellungId)) {
      res.status(400).json({ success: false, message: 'Ungültige Bestellungs-ID' });
      return;
    }
    try {
      const history = await bestellungService.getHistory(bestellungId);
      res.status(200).json({ success: true, data: history });
    } catch (error) {
      logger.error('BestellungController.getHistory error', { error });
      res.status(500).json({ success: false, message: 'Historie konnte nicht geladen werden' });
    }
  }

  // ---------------------------------------------------------------------------
  // Export (placeholder — returns order detail as JSON for now)
  // ---------------------------------------------------------------------------

  async exportOrder(req: Request, res: Response): Promise<void> {
    const id = parseInt(param(req, 'id'), 10);
    if (isNaN(id)) {
      res.status(400).json({ success: false, message: 'Ungültige ID' });
      return;
    }
    try {
      const order = await bestellungService.getOrderById(id);
      if (!order) {
        res.status(404).json({ success: false, message: 'Bestellung nicht gefunden' });
        return;
      }
      const orderStatus = order.bestellung.status;
      if (orderStatus === 'entwurf' || orderStatus === 'wartet_auf_genehmigung') {
        res.status(403).json({ success: false, message: 'Export nur nach Genehmigung verfügbar' });
        return;
      }
      res.status(200).json({ success: true, data: order });
    } catch (error) {
      logger.error('BestellungController.exportOrder error', { error });
      res.status(500).json({ success: false, message: 'Export fehlgeschlagen' });
    }
  }
}

export default new BestellungController();
