// AS4 Member Directory Service
// Manages member registry, endpoints, certificates, and routing configuration

import prisma from '@/shared/database/prisma';
import { v4 as uuidv4 } from 'uuid';
import { DbisError, ErrorCode } from '@/shared/types';
import { logger } from '@/infrastructure/monitoring/logger';

export interface MemberRecord {
  memberId: string;
  organizationName: string;
  capacityTier?: number;
  status: 'active' | 'suspended' | 'terminated';
  as4EndpointUrl: string;
  tlsCertFingerprint: string;
  signingCertFingerprint?: string;
  encryptionCertFingerprint?: string;
  allowedMessageTypes: string[];
  supportedCurrencies?: string[];
  cutoffWindows?: CutoffWindow[];
  routingGroups: string[];
  createdAt: Date;
  updatedAt: Date;
}

export interface CutoffWindow {
  corridor: string;
  currency: string;
  cutoffTime: string; // HH:mm UTC
  valueDateRule: 'same-day' | 'next-day';
  timezone?: string;
}

export interface MemberSearchFilters {
  status?: string;
  capacityTier?: number;
  routingGroup?: string;
}

export class MemberDirectoryService {
  /**
   * Get member by ID
   */
  async getMember(memberId: string): Promise<MemberRecord | null> {
    const member = await prisma.as4Member.findUnique({
      where: { memberId },
      include: {
        certificates: {
          where: { status: 'active' },
          orderBy: { validTo: 'desc' },
        },
      },
    });

    if (!member) {
      return null;
    }

    const signingCert = member.certificates.find((c) => c.certificateType === 'SIGNING');
    const encryptionCert = member.certificates.find((c) => c.certificateType === 'ENCRYPTION');

    return {
      memberId: member.memberId,
      organizationName: member.organizationName,
      capacityTier: member.capacityTier || undefined,
      status: member.status as 'active' | 'suspended' | 'terminated',
      as4EndpointUrl: member.as4EndpointUrl,
      tlsCertFingerprint: member.tlsCertFingerprint,
      signingCertFingerprint: signingCert?.fingerprint,
      encryptionCertFingerprint: encryptionCert?.fingerprint,
      allowedMessageTypes: member.allowedMessageTypes,
      supportedCurrencies: [],
      cutoffWindows: (member.cutoffWindows as CutoffWindow[]) || [],
      routingGroups: member.routingGroups,
      createdAt: member.createdAt,
      updatedAt: member.updatedAt,
    };
  }

  /**
   * Search members
   */
  async searchMembers(filters: MemberSearchFilters): Promise<MemberRecord[]> {
    const where: any = {};

    if (filters.status) {
      where.status = filters.status;
    }

    if (filters.capacityTier) {
      where.capacityTier = filters.capacityTier;
    }

    if (filters.routingGroup) {
      where.routingGroups = {
        has: filters.routingGroup,
      };
    }

    const members = await prisma.as4Member.findMany({
      where,
      include: {
        certificates: {
          where: { status: 'active' },
          orderBy: { validTo: 'desc' },
        },
      },
    });

    return members.map((member) => {
      const signingCert = member.certificates.find((c) => c.certificateType === 'SIGNING');
      const encryptionCert = member.certificates.find((c) => c.certificateType === 'ENCRYPTION');

      return {
        memberId: member.memberId,
        organizationName: member.organizationName,
        capacityTier: member.capacityTier || undefined,
        status: member.status as 'active' | 'suspended' | 'terminated',
        as4EndpointUrl: member.as4EndpointUrl,
        tlsCertFingerprint: member.tlsCertFingerprint,
        signingCertFingerprint: signingCert?.fingerprint,
        encryptionCertFingerprint: encryptionCert?.fingerprint,
        allowedMessageTypes: member.allowedMessageTypes,
        supportedCurrencies: [],
        cutoffWindows: (member.cutoffWindows as CutoffWindow[]) || [],
        routingGroups: member.routingGroups,
        createdAt: member.createdAt,
        updatedAt: member.updatedAt,
      };
    });
  }

  /**
   * Register new member
   */
  async registerMember(data: {
    memberId: string;
    organizationName: string;
    as4EndpointUrl: string;
    tlsCertFingerprint: string;
    allowedMessageTypes: string[];
    routingGroups?: string[];
    capacityTier?: number;
    cutoffWindows?: CutoffWindow[];
  }): Promise<MemberRecord> {
    // Check if member already exists
    const existing = await prisma.as4Member.findUnique({
      where: { memberId: data.memberId },
    });

    if (existing) {
      throw new DbisError(ErrorCode.VALIDATION_ERROR, `Member ${data.memberId} already exists`);
    }

    const member = await prisma.as4Member.create({
      data: {
        id: uuidv4(),
        memberId: data.memberId,
        organizationName: data.organizationName,
        as4EndpointUrl: data.as4EndpointUrl,
        tlsCertFingerprint: data.tlsCertFingerprint,
        allowedMessageTypes: data.allowedMessageTypes,
        routingGroups: data.routingGroups || [],
        capacityTier: data.capacityTier,
        cutoffWindows: data.cutoffWindows || [],
        status: 'active',
      },
      include: {
        certificates: true,
      },
    });

    logger.info('AS4 member registered', {
      memberId: member.memberId,
      organizationName: member.organizationName,
    });

    return {
      memberId: member.memberId,
      organizationName: member.organizationName,
      capacityTier: member.capacityTier || undefined,
      status: member.status as 'active' | 'suspended' | 'terminated',
      as4EndpointUrl: member.as4EndpointUrl,
      tlsCertFingerprint: member.tlsCertFingerprint,
      allowedMessageTypes: member.allowedMessageTypes,
      supportedCurrencies: [],
      cutoffWindows: (member.cutoffWindows as CutoffWindow[]) || [],
      routingGroups: member.routingGroups,
      createdAt: member.createdAt,
      updatedAt: member.updatedAt,
    };
  }

  /**
   * Update member
   */
  async updateMember(memberId: string, updates: Partial<MemberRecord>): Promise<MemberRecord> {
    const member = await prisma.as4Member.findUnique({
      where: { memberId },
    });

    if (!member) {
      throw new DbisError(ErrorCode.NOT_FOUND, `Member ${memberId} not found`);
    }

    const updated = await prisma.as4Member.update({
      where: { memberId },
      data: {
        organizationName: updates.organizationName,
        as4EndpointUrl: updates.as4EndpointUrl,
        tlsCertFingerprint: updates.tlsCertFingerprint,
        allowedMessageTypes: updates.allowedMessageTypes,
        routingGroups: updates.routingGroups,
        cutoffWindows: updates.cutoffWindows,
        status: updates.status,
        capacityTier: updates.capacityTier,
      },
      include: {
        certificates: {
          where: { status: 'active' },
          orderBy: { validTo: 'desc' },
        },
      },
    });

    const signingCert = updated.certificates.find((c) => c.certificateType === 'SIGNING');
    const encryptionCert = updated.certificates.find((c) => c.certificateType === 'ENCRYPTION');

    return {
      memberId: updated.memberId,
      organizationName: updated.organizationName,
      capacityTier: updated.capacityTier || undefined,
      status: updated.status as 'active' | 'suspended' | 'terminated',
      as4EndpointUrl: updated.as4EndpointUrl,
      tlsCertFingerprint: updated.tlsCertFingerprint,
      signingCertFingerprint: signingCert?.fingerprint,
      encryptionCertFingerprint: encryptionCert?.fingerprint,
      allowedMessageTypes: updated.allowedMessageTypes,
      supportedCurrencies: [],
      cutoffWindows: (updated.cutoffWindows as CutoffWindow[]) || [],
      routingGroups: updated.routingGroups,
      createdAt: updated.createdAt,
      updatedAt: updated.updatedAt,
    };
  }

  /**
   * Get member certificates
   */
  async getMemberCertificates(memberId: string) {
    const member = await prisma.as4Member.findUnique({
      where: { memberId },
      include: {
        certificates: {
          orderBy: { validTo: 'desc' },
        },
      },
    });

    if (!member) {
      throw new DbisError(ErrorCode.NOT_FOUND, `Member ${memberId} not found`);
    }

    return member.certificates;
  }

  /**
   * Add certificate to member
   */
  async addCertificate(memberId: string, data: {
    certificateType: 'TLS' | 'SIGNING' | 'ENCRYPTION';
    fingerprint: string;
    certificateData?: string;
    validFrom: Date;
    validTo: Date;
  }) {
    const member = await prisma.as4Member.findUnique({
      where: { memberId },
    });

    if (!member) {
      throw new DbisError(ErrorCode.NOT_FOUND, `Member ${memberId} not found`);
    }

    // Revoke old certificates of same type
    await prisma.as4MemberCertificate.updateMany({
      where: {
        memberId,
        certificateType: data.certificateType,
        status: 'active',
      },
      data: {
        status: 'revoked',
        revokedAt: new Date(),
      },
    });

    const certificate = await prisma.as4MemberCertificate.create({
      data: {
        id: uuidv4(),
        memberId,
        certificateType: data.certificateType,
        fingerprint: data.fingerprint,
        certificateData: data.certificateData,
        validFrom: data.validFrom,
        validTo: data.validTo,
        status: 'active',
      },
    });

    logger.info('AS4 certificate added', {
      memberId,
      certificateType: data.certificateType,
      fingerprint: data.fingerprint,
    });

    return certificate;
  }

  /**
   * Validate member endpoint
   */
  async validateMemberEndpoint(memberId: string): Promise<boolean> {
    const member = await prisma.as4Member.findUnique({
      where: { memberId },
    });

    if (!member || member.status !== 'active') {
      return false;
    }

    // TODO: Add actual endpoint health check
    return true;
  }
}

export const memberDirectoryService = new MemberDirectoryService();
