import { Request, Response } from 'express';
import { z } from 'zod';
import personalEquipmentService from '../services/personalEquipment.service';
import settingsService from '../services/settings.service';
import logger from '../utils/logger';

const uuidString = z.string().regex(
  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
  'Ungültige UUID',
);

const isoDate = z.string().regex(
  /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/,
  'Erwartet ISO-Datum im Format YYYY-MM-DD',
);

const ZustandEnum = z.string().min(1).max(50);

const EigenschaftInput = z.object({
  eigenschaft_id: z.number().int().positive().nullable().optional(),
  name:           z.string().min(1).max(200),
  wert:           z.string().max(500),
});

const CreateSchema = z.object({
  bezeichnung:       z.string().min(1).max(200),
  kategorie:         z.string().max(100).optional(),
  artikel_id:        z.number().int().positive().optional(),
  user_id:           uuidString.optional(),
  benutzer_name:     z.string().max(200).optional(),
  groesse:           z.string().max(50).optional(),
  seriennummer:      z.string().max(100).optional(),
  inventarnummer:    z.string().max(50).optional(),
  anschaffung_datum: isoDate.optional(),
  zustand:           ZustandEnum.optional(),
  notizen:           z.string().max(2000).optional(),
  eigenschaften:     z.array(EigenschaftInput).optional(),
});

const UpdateSchema = z.object({
  bezeichnung:       z.string().min(1).max(200).optional(),
  kategorie:         z.string().max(100).nullable().optional(),
  artikel_id:        z.number().int().positive().nullable().optional(),
  user_id:           uuidString.nullable().optional(),
  benutzer_name:     z.string().max(200).nullable().optional(),
  groesse:           z.string().max(50).nullable().optional(),
  seriennummer:      z.string().max(100).nullable().optional(),
  inventarnummer:    z.string().max(50).nullable().optional(),
  anschaffung_datum: isoDate.nullable().optional(),
  zustand:           ZustandEnum.optional(),
  notizen:           z.string().max(2000).nullable().optional(),
  eigenschaften:     z.array(EigenschaftInput).nullable().optional(),
});

function isValidUUID(s: string): boolean {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);
}

class PersonalEquipmentController {
  async list(req: Request, res: Response): Promise<void> {
    try {
      const filters: Record<string, string> = {};
      if (req.query.user_id) filters.userId = String(req.query.user_id);
      if (req.query.kategorie) filters.kategorie = String(req.query.kategorie);
      if (req.query.zustand) filters.zustand = String(req.query.zustand);

      const items = await personalEquipmentService.getAll(filters);
      res.status(200).json({ success: true, data: items });
    } catch (error) {
      logger.error('personalEquipment.list error', { error });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' });
    }
  }

  async getMy(req: Request, res: Response): Promise<void> {
    try {
      const items = await personalEquipmentService.getByUserId(req.user!.id);
      res.status(200).json({ success: true, data: items });
    } catch (error) {
      logger.error('personalEquipment.getMy error', { error });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' });
    }
  }

  async getByUser(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      if (!isValidUUID(userId)) {
        res.status(400).json({ success: false, message: 'Ungültige User-ID' });
        return;
      }
      const items = await personalEquipmentService.getByUserId(userId);
      res.status(200).json({ success: true, data: items });
    } catch (error) {
      logger.error('personalEquipment.getByUser error', { error });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' });
    }
  }

  async getById(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params as Record<string, string>;
      if (!isValidUUID(id)) {
        res.status(400).json({ success: false, message: 'Ungültige ID' });
        return;
      }
      const item = await personalEquipmentService.getById(id);
      if (!item) {
        res.status(404).json({ success: false, message: 'Nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: item });
    } catch (error) {
      logger.error('personalEquipment.getById error', { error });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht geladen werden' });
    }
  }

  async create(req: Request, res: Response): Promise<void> {
    try {
      const parsed = CreateSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({ success: false, message: 'Validierungsfehler', errors: parsed.error.flatten().fieldErrors });
        return;
      }
      const item = await personalEquipmentService.create(parsed.data, req.user!.id);
      res.status(201).json({ success: true, data: item });
    } catch (error) {
      logger.error('personalEquipment.create error', { error });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht erstellt werden' });
    }
  }

  async update(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params as Record<string, string>;
      if (!isValidUUID(id)) {
        res.status(400).json({ success: false, message: 'Ungültige ID' });
        return;
      }
      const parsed = UpdateSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({ success: false, message: 'Validierungsfehler', errors: parsed.error.flatten().fieldErrors });
        return;
      }
      if (Object.keys(parsed.data).length === 0) {
        res.status(400).json({ success: false, message: 'Kein Feld zum Aktualisieren angegeben' });
        return;
      }
      const item = await personalEquipmentService.update(id, parsed.data as any);
      if (!item) {
        res.status(404).json({ success: false, message: 'Nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, data: item });
    } catch (error: any) {
      if (error?.message === 'No fields to update') {
        res.status(400).json({ success: false, message: 'Kein Feld zum Aktualisieren angegeben' });
        return;
      }
      logger.error('personalEquipment.update error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht aktualisiert werden' });
    }
  }

  async delete(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params as Record<string, string>;
      if (!isValidUUID(id)) {
        res.status(400).json({ success: false, message: 'Ungültige ID' });
        return;
      }
      const deleted = await personalEquipmentService.delete(id);
      if (!deleted) {
        res.status(404).json({ success: false, message: 'Nicht gefunden' });
        return;
      }
      res.status(200).json({ success: true, message: 'Persönliche Ausrüstung gelöscht' });
    } catch (error) {
      logger.error('personalEquipment.delete error', { error, id: req.params.id });
      res.status(500).json({ success: false, message: 'Persönliche Ausrüstung konnte nicht gelöscht werden' });
    }
  }

  async getZustandOptions(_req: Request, res: Response): Promise<void> {
    try {
      const setting = await settingsService.get('personal_equipment_zustand_options');
      const options = Array.isArray(setting?.value) ? setting!.value : [
        { key: 'gut', label: 'Gut', color: 'success' },
        { key: 'beschaedigt', label: 'Beschädigt', color: 'warning' },
        { key: 'abgaengig', label: 'Abgängig', color: 'error' },
        { key: 'verloren', label: 'Verloren', color: 'default' },
      ];
      res.status(200).json({ success: true, data: options });
    } catch (error) {
      logger.error('personalEquipment.getZustandOptions error', { error });
      res.status(500).json({ success: false, message: 'Zustände konnten nicht geladen werden' });
    }
  }

  async updateZustandOptions(req: Request, res: Response): Promise<void> {
    try {
      const schema = z.array(z.object({
        key: z.string().min(1).max(50),
        label: z.string().min(1).max(100),
        color: z.enum(['success', 'warning', 'error', 'default', 'primary', 'secondary', 'info']),
      })).min(1);
      const parsed = schema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({ success: false, message: 'Validierungsfehler', errors: parsed.error.flatten() });
        return;
      }
      await settingsService.set('personal_equipment_zustand_options', parsed.data, req.user!.id);
      res.status(200).json({ success: true, data: parsed.data });
    } catch (error) {
      logger.error('personalEquipment.updateZustandOptions error', { error });
      res.status(500).json({ success: false, message: 'Zustände konnten nicht gespeichert werden' });
    }
  }
}

export default new PersonalEquipmentController();
