import { Request, Response } from 'express';
import memberService from '../services/member.service';
import logger from '../utils/logger';
import {
  CreateMemberProfileSchema,
  UpdateMemberProfileSchema,
  SelfUpdateMemberProfileSchema,
} from '../models/member.model';

// ----------------------------------------------------------------
// Role helpers
// These helpers inspect req.user.role which is populated by the
// requireRole / requirePermission middleware (see member.routes.ts).
// ----------------------------------------------------------------

type AppRole = 'admin' | 'kommandant' | 'mitglied';

function getRole(req: Request): AppRole {
  // req.userRole is set by requirePermission() for non-owner paths.
  // Fall back to req.user.role (JWT claim) and finally to 'mitglied'.
  return (req as any).userRole ?? (req.user as any)?.role ?? 'mitglied';
}

function canWrite(req: Request): boolean {
  const role = getRole(req);
  return role === 'admin' || role === 'kommandant';
}

function isOwnProfile(req: Request, userId: string): boolean {
  return req.user?.id === userId;
}

// ----------------------------------------------------------------
// Controller
// ----------------------------------------------------------------
class MemberController {
  /**
   * GET /api/members
   * Returns a paginated list of all active members.
   * Supports ?search=, ?status[]=, ?dienstgrad[]=, ?page=, ?pageSize=
   */
  async getMembers(req: Request, res: Response): Promise<void> {
    try {
      const {
        search,
        page,
        pageSize,
      } = req.query as Record<string, string | undefined>;

      // Arrays can be sent as ?status[]=aktiv&status[]=jugend or CSV
      const statusParam = req.query['status'] as string | string[] | undefined;
      const dienstgradParam = req.query['dienstgrad'] as string | string[] | undefined;

      const normalizeArray = (v?: string | string[]): string[] | undefined => {
        if (!v) return undefined;
        return Array.isArray(v) ? v : v.split(',').map((s) => s.trim()).filter(Boolean);
      };

      const { items, total } = await memberService.getAllMembers({
        search,
        status: normalizeArray(statusParam) as any,
        dienstgrad: normalizeArray(dienstgradParam) as any,
        page: page ? parseInt(page, 10) || 1 : 1,
        pageSize: pageSize ? (parseInt(pageSize, 10) === 0 ? 0 : Math.min(parseInt(pageSize, 10) || 25, 100)) : 25,
      });

      res.status(200).json({
        success: true,
        data: items,
        meta: { total, page: page ? parseInt(page, 10) : 1 },
      });
    } catch (error) {
      logger.error('getMembers error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Mitglieder.' });
    }
  }

  /**
   * GET /api/members/stats
   * Returns aggregate member counts for each status.
   * Must be registered BEFORE /:userId to avoid route collision.
   */
  async getMemberStats(_req: Request, res: Response): Promise<void> {
    try {
      const stats = await memberService.getMemberStats();
      res.status(200).json({ success: true, data: stats });
    } catch (error) {
      logger.error('getMemberStats error', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Statistiken.' });
    }
  }

  /**
   * GET /api/members/:userId
   * Returns full member detail including profile and rank history.
   *
   * Role rules:
   * - Kommandant/Admin: all fields
   * - Mitglied reading own profile: all fields
   * - Mitglied reading another member: geburtsdatum and emergency contact redacted
   */
  async getMemberById(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      const ownProfile = isOwnProfile(req, userId);

      const member = await memberService.getMemberById(userId);

      if (!member) {
        res.status(404).json({ success: false, message: 'Mitglied nicht gefunden.' });
        return;
      }

      // Sensitive field masking for non-privileged reads of other members
      const canReadSensitive = canWrite(req) || ownProfile;

      if (!canReadSensitive && member.profile) {
        // Replace geburtsdatum with only the age (year of birth omitted for DSGVO)
        const ageMasked: any = { ...member.profile };

        if (ageMasked.geburtsdatum) {
          const birthYear = new Date(ageMasked.geburtsdatum).getFullYear();
          const age = new Date().getFullYear() - birthYear;
          ageMasked.geburtsdatum = null;
          ageMasked._age = age; // synthesised non-DB field
        }

        // Redact emergency contact entirely
        ageMasked.notfallkontakt_name = null;
        ageMasked.notfallkontakt_telefon = null;

        res.status(200).json({
          success: true,
          data: { ...member, profile: ageMasked },
        });
        return;
      }

      res.status(200).json({ success: true, data: member });
    } catch (error) {
      logger.error('getMemberById error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Laden des Mitglieds.' });
    }
  }

  /**
   * POST /api/members/:userId/profile
   * Creates the mitglieder_profile row for an existing auth user.
   * Restricted to Kommandant/Admin.
   */
  async createMemberProfile(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;

      const parseResult = CreateMemberProfileSchema.safeParse(req.body);
      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Ungültige Eingabedaten.',
          errors: parseResult.error.flatten().fieldErrors,
        });
        return;
      }

      const profile = await memberService.createMemberProfile(userId, parseResult.data);
      logger.info('createMemberProfile', { userId, createdBy: req.user!.id });

      res.status(201).json({ success: true, data: profile });
    } catch (error: any) {
      if (error?.message?.includes('existiert bereits')) {
        res.status(409).json({ success: false, message: error.message });
        return;
      }
      logger.error('createMemberProfile error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Erstellen des Profils.' });
    }
  }

  /**
   * PATCH /api/members/:userId
   * Updates the mitglieder_profile row.
   *
   * Role rules:
   * - Kommandant/Admin: full update (all fields)
   * - Mitglied (own profile only): restricted to SelfUpdateMemberProfileSchema fields
   */
  async updateMember(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      const updaterId = req.user!.id;
      const ownProfile = isOwnProfile(req, userId);

      if (!canWrite(req) && !ownProfile) {
        res.status(403).json({
          success: false,
          message: 'Keine Berechtigung, dieses Profil zu bearbeiten.',
        });
        return;
      }

      // Choose validation schema based on role
      const schema = canWrite(req) ? UpdateMemberProfileSchema : SelfUpdateMemberProfileSchema;
      const parseResult = schema.safeParse(req.body);

      if (!parseResult.success) {
        res.status(400).json({
          success: false,
          message: 'Ungültige Eingabedaten.',
          errors: parseResult.error.flatten().fieldErrors,
        });
        return;
      }

      await memberService.updateMemberProfile(
        userId,
        parseResult.data as any,
        updaterId
      );

      // Return full MemberWithProfile so the frontend state stays consistent
      const fullMember = await memberService.getMemberById(userId);
      logger.info('updateMember', { userId, updatedBy: updaterId });
      res.status(200).json({ success: true, data: fullMember });
    } catch (error: any) {
      if (error?.message === 'Mitgliedsprofil nicht gefunden.') {
        res.status(404).json({ success: false, message: error.message });
        return;
      }
      logger.error('updateMember error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Aktualisieren des Profils.' });
    }
  }
  /**
   * GET /api/members/:userId/befoerderungen
   */
  async getBefoerderungen(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      const data = await memberService.getBefoerderungen(userId);
      res.status(200).json({ success: true, data });
    } catch (error) {
      logger.error('getBefoerderungen error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Beförderungen.' });
    }
  }

  /**
   * GET /api/members/:userId/untersuchungen
   */
  async getUntersuchungen(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      const data = await memberService.getUntersuchungen(userId);
      res.status(200).json({ success: true, data });
    } catch (error) {
      logger.error('getUntersuchungen error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Untersuchungen.' });
    }
  }

  /**
   * GET /api/members/:userId/fahrgenehmigungen
   */
  async getFahrgenehmigungen(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      const data = await memberService.getFahrgenehmigungen(userId);
      res.status(200).json({ success: true, data });
    } catch (error) {
      logger.error('getFahrgenehmigungen error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Fahrgenehmigungen.' });
    }
  }

  /**
   * GET /api/members/:userId/ausbildungen
   */
  async getAusbildungen(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params as Record<string, string>;
      const data = await memberService.getAusbildungen(userId);
      res.status(200).json({ success: true, data });
    } catch (error) {
      logger.error('getAusbildungen error', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Ausbildungen.' });
    }
  }
}

export default new MemberController();
