/**
 * eResidency and eCitizenship Verifiable Credential Schemas
 * Based on W3C Verifiable Credentials Data Model
 * Version 0.9 - MVP Schema Registry
 */

import { z } from 'zod';

/**
 * Levels of Assurance (LOA)
 */
export enum LevelOfAssurance {
  LOA1 = 'LOA1', // Basic identity verification
  LOA2 = 'LOA2', // Enhanced identity verification with document check
  LOA3 = 'LOA3', // Highest level with in-person or video verification
}

/**
 * Membership Classes
 */
export enum MembershipClass {
  RESIDENT = 'Resident',
  CITIZEN = 'Citizen',
  HONORARY = 'Honorary',
  SERVICE = 'Service',
}

/**
 * Evidence Types
 */
export enum EvidenceType {
  DocumentVerification = 'DocumentVerification',
  LivenessCheck = 'LivenessCheck',
  SanctionsScreen = 'SanctionsScreen',
  VideoInterview = 'VideoInterview',
  Sponsorship = 'Sponsorship',
  ResidencyTenure = 'ResidencyTenure',
  BackgroundAttestation = 'BackgroundAttestation',
}

/**
 * Evidence Result
 */
export enum EvidenceResult {
  pass = 'pass',
  fail = 'fail',
  manual = 'manual',
}

/**
 * eResident Credential Subject (v0.9)
 * Matches DSB Schema Registry specification
 */
export const eResidentCredentialSubjectSchema = z.object({
  id: z.string().describe('DID of the eResident'),
  legalName: z.string().describe('Legal name of the eResident'),
  publicHandle: z.string().optional().describe('Optional pseudonymous public handle'),
  assuranceLevel: z.enum([LevelOfAssurance.LOA1, LevelOfAssurance.LOA2]).describe('Level of Assurance'),
  residentNumber: z.string().describe('Unique resident number'),
  issueJurisdiction: z.literal('DSB').describe('Issuing jurisdiction'),
});

export type eResidentCredentialSubject = z.infer<typeof eResidentCredentialSubjectSchema>;

/**
 * eCitizen Credential Subject (v0.9)
 * Matches DSB Schema Registry specification
 */
export const eCitizenCredentialSubjectSchema = z.object({
  id: z.string().describe('DID of the eCitizen'),
  citizenNumber: z.string().describe('Unique citizen number'),
  assuranceLevel: z.enum([LevelOfAssurance.LOA2, LevelOfAssurance.LOA3]).describe('Level of Assurance (minimum LOA2)'),
  oathDate: z.string().describe('ISO 8601 date when oath was taken'),
  governanceRights: z.array(z.string()).optional().describe('Governance rights granted'),
  sponsoringMember: z.string().optional().describe('DID of the sponsoring member if applicable'),
});

export type eCitizenCredentialSubject = z.infer<typeof eCitizenCredentialSubjectSchema>;

/**
 * Evidence Schema
 */
export const evidenceSchema = z.object({
  type: z.nativeEnum(EvidenceType),
  verifier: z.string().optional().describe('DID or identifier of the verifier'),
  txn: z.string().optional().describe('Transaction ID or reference'),
  result: z.nativeEnum(EvidenceResult),
  timestamp: z.string().optional().describe('ISO 8601 timestamp of the evidence'),
});

export type Evidence = z.infer<typeof evidenceSchema>;

/**
 * Address Attestation Credential Subject
 */
export const addressAttestationCredentialSubjectSchema = z.object({
  id: z.string().describe('DID of the subject'),
  address: z.object({
    street: z.string(),
    city: z.string(),
    region: z.string().optional(),
    postalCode: z.string(),
    country: z.string(),
  }),
  attestedSince: z.string().describe('ISO 8601 date when address was attested'),
  attestedUntil: z.string().optional().describe('ISO 8601 date when attestation expires'),
  attestedBy: z.string().describe('DID of the attesting authority'),
});

export type AddressAttestationCredentialSubject = z.infer<
  typeof addressAttestationCredentialSubjectSchema
>;

/**
 * Good Standing Credential Subject
 */
export const goodStandingCredentialSubjectSchema = z.object({
  id: z.string().describe('DID of the subject'),
  membershipClass: z.nativeEnum(MembershipClass),
  goodStanding: z.boolean(),
  verifiedSince: z.string().describe('ISO 8601 date when good standing was verified'),
  verifiedUntil: z.string().optional().describe('ISO 8601 date when verification expires'),
  complianceChecks: z
    .array(
      z.object({
        check: z.string(),
        passed: z.boolean(),
        checkedAt: z.string(),
      })
    )
    .optional(),
});

export type GoodStandingCredentialSubject = z.infer<typeof goodStandingCredentialSubjectSchema>;

/**
 * Professional Order Credential Subject
 */
export const professionalOrderCredentialSubjectSchema = z.object({
  id: z.string().describe('DID of the subject'),
  order: z.string().describe('Name of the professional order'),
  role: z.string().describe('Role within the order'),
  membershipSince: z.string().describe('ISO 8601 date when membership began'),
  membershipUntil: z.string().optional().describe('ISO 8601 date when membership expires'),
  credentials: z.array(z.string()).optional().describe('Professional credentials held'),
  status: z.enum(['active', 'suspended', 'revoked', 'expired']),
});

export type ProfessionalOrderCredentialSubject = z.infer<
  typeof professionalOrderCredentialSubjectSchema
>;

/**
 * eResident Credential Schema (v0.9)
 * Matches DSB Schema Registry specification
 */
export const eResidentCredentialSchema = z.object({
  '@context': z.array(z.string()).min(1),
  type: z.array(z.string()).refine((arr) => arr.includes('VerifiableCredential') && arr.includes('eResidentCredential'), {
    message: 'Type must include VerifiableCredential and eResidentCredential',
  }),
  issuer: z.string().describe('DID of the issuing authority'),
  issuanceDate: z.string().describe('ISO 8601 date when credential was issued'),
  expirationDate: z.string().optional().describe('ISO 8601 date when credential expires'),
  credentialSubject: eResidentCredentialSubjectSchema,
  credentialStatus: z
    .object({
      id: z.string(),
      type: z.string(),
    })
    .optional(),
  evidence: z.array(evidenceSchema).optional().describe('Evidence supporting the credential'),
  proof: z.object({
    type: z.string(),
    created: z.string(),
    proofPurpose: z.string(),
    verificationMethod: z.string(),
    jws: z.string().optional(),
  }),
});

export type eResidentCredential = z.infer<typeof eResidentCredentialSchema>;

/**
 * eCitizen Credential Schema (v0.9)
 * Matches DSB Schema Registry specification
 */
export const eCitizenCredentialSchema = z.object({
  '@context': z.array(z.string()).min(1),
  type: z.array(z.string()).refine((arr) => arr.includes('VerifiableCredential') && arr.includes('eCitizenCredential'), {
    message: 'Type must include VerifiableCredential and eCitizenCredential',
  }),
  issuer: z.string().describe('DID of the issuing authority'),
  issuanceDate: z.string().describe('ISO 8601 date when credential was issued'),
  expirationDate: z.string().optional().describe('ISO 8601 date when credential expires'),
  credentialSubject: eCitizenCredentialSubjectSchema,
  credentialStatus: z
    .object({
      id: z.string(),
      type: z.string(),
    })
    .optional(),
  evidence: z.array(evidenceSchema).optional().describe('Evidence supporting the credential'),
  proof: z.object({
    type: z.string(),
    created: z.string(),
    proofPurpose: z.string(),
    verificationMethod: z.string(),
    jws: z.string().optional(),
  }),
});

export type eCitizenCredential = z.infer<typeof eCitizenCredentialSchema>;

/**
 * Verifiable Presentation Schema
 */
export const verifiablePresentationSchema = z.object({
  '@context': z.array(z.string()).min(1),
  type: z.array(z.string()).refine((arr) => arr.includes('VerifiablePresentation'), {
    message: 'Type must include VerifiablePresentation',
  }),
  verifiableCredential: z.array(z.union([eResidentCredentialSchema, eCitizenCredentialSchema])).min(1),
  holder: z.string().describe('DID of the holder'),
  proof: z.object({
    type: z.string(),
    created: z.string(),
    challenge: z.string().optional(),
    proofPurpose: z.string(),
    verificationMethod: z.string(),
    jws: z.string().optional(),
  }),
});

export type VerifiablePresentation = z.infer<typeof verifiablePresentationSchema>;

/**
 * Application Status
 */
export enum ApplicationStatus {
  DRAFT = 'draft',
  SUBMITTED = 'submitted',
  UNDER_REVIEW = 'under_review',
  KYC_PENDING = 'kyc_pending',
  APPROVED = 'approved',
  REJECTED = 'rejected',
  APPEALED = 'appealed',
  CANCELLED = 'cancelled',
}

/**
 * eResidency Application Schema
 */
export const eResidencyApplicationSchema = z.object({
  id: z.string().uuid(),
  applicantDid: z.string().optional(),
  email: z.string().email(),
  givenName: z.string(),
  familyName: z.string(),
  dateOfBirth: z.string().optional(),
  nationality: z.string().optional(),
  phone: z.string().optional(),
  address: z
    .object({
      street: z.string().optional(),
      city: z.string().optional(),
      region: z.string().optional(),
      postalCode: z.string().optional(),
      country: z.string().optional(),
    })
    .optional(),
  deviceFingerprint: z.string().optional(),
  identityDocument: z
    .object({
      type: z.enum(['passport', 'national_id', 'drivers_license']),
      number: z.string(),
      issuingCountry: z.string(),
      expiryDate: z.string().optional(),
      documentHash: z.string().optional(),
    })
    .optional(),
  selfieLiveness: z
    .object({
      imageHash: z.string(),
      livenessScore: z.number().min(0).max(1),
      verifiedAt: z.string(),
    })
    .optional(),
  status: z.nativeEnum(ApplicationStatus),
  submittedAt: z.string().optional(),
  reviewedAt: z.string().optional(),
  reviewedBy: z.string().optional(),
  rejectionReason: z.string().optional(),
  kycStatus: z.enum(['pending', 'passed', 'failed', 'requires_edd']).optional(),
  sanctionsStatus: z.enum(['pending', 'clear', 'flag']).optional(),
  pepStatus: z.enum(['pending', 'clear', 'flag']).optional(),
  riskScore: z.number().min(0).max(1).optional(),
  kycResults: z.record(z.unknown()).optional(),
  sanctionsResults: z.record(z.unknown()).optional(),
  riskAssessment: z.record(z.unknown()).optional(),
  createdAt: z.string(),
  updatedAt: z.string(),
});

export type eResidencyApplication = z.infer<typeof eResidencyApplicationSchema>;

/**
 * eCitizenship Application Schema
 */
export const eCitizenshipApplicationSchema = z.object({
  id: z.string().uuid(),
  applicantDid: z.string(),
  residentDid: z.string().describe('DID of the eResident applying for citizenship'),
  residencyTenure: z.number().describe('Months as eResident'),
  sponsorDid: z.string().optional().describe('DID of the sponsor if applicable'),
  serviceMerit: z
    .object({
      serviceHours: z.number(),
      contributions: z.array(z.string()),
    })
    .optional(),
  videoInterview: z
    .object({
      scheduledAt: z.string().optional(),
      completedAt: z.string().optional(),
      recordingHash: z.string().optional(),
      interviewerDid: z.string().optional(),
    })
    .optional(),
  backgroundAttestations: z
    .array(
      z.object({
        attesterDid: z.string(),
        attestation: z.string(),
        attestedAt: z.string(),
      })
    )
    .optional(),
  oathCeremony: z
    .object({
      scheduledAt: z.string().optional(),
      completedAt: z.string().optional(),
      ceremonyHash: z.string().optional(),
      oathVersion: z.string().optional(),
    })
    .optional(),
  status: z.nativeEnum(ApplicationStatus),
  submittedAt: z.string().optional(),
  reviewedAt: z.string().optional(),
  reviewedBy: z.string().optional(),
  rejectionReason: z.string().optional(),
  createdAt: z.string(),
  updatedAt: z.string(),
});

export type eCitizenshipApplication = z.infer<typeof eCitizenshipApplicationSchema>;

