import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
import type { MembershipRoleValue } from '@core/racing/domain/entities/MembershipRole';
import type { MembershipStatusValue } from '@core/racing/domain/entities/MembershipStatus';

import { LeagueMembershipOrmEntity } from '../entities/LeagueMembershipOrmEntity';
import { InvalidLeagueMembershipSchemaError } from '../errors/InvalidLeagueMembershipSchemaError';

function isNonEmptyString(value: unknown): value is string {
  return typeof value === 'string' && value.trim().length > 0;
}

const VALID_ROLES: readonly MembershipRoleValue[] = ['owner', 'admin', 'steward', 'member'] as const;

const VALID_STATUSES: readonly MembershipStatusValue[] = ['active', 'inactive', 'pending'] as const;

function isOneOf<T extends string>(value: string, allowed: readonly T[]): value is T {
  return (allowed as readonly string[]).includes(value);
}

export class LeagueMembershipOrmMapper {
  toOrmEntity(domain: LeagueMembership): LeagueMembershipOrmEntity {
    const entity = new LeagueMembershipOrmEntity();
    entity.id = domain.id;
    entity.leagueId = domain.leagueId.toString();
    entity.driverId = domain.driverId.toString();
    entity.role = domain.role.toString();
    entity.status = domain.status.toString();
    entity.joinedAt = domain.joinedAt.toDate();
    return entity;
  }

  toDomain(entity: LeagueMembershipOrmEntity): LeagueMembership {
    if (!isNonEmptyString(entity.id)) {
      throw new InvalidLeagueMembershipSchemaError('Invalid id');
    }
    if (!isNonEmptyString(entity.leagueId)) {
      throw new InvalidLeagueMembershipSchemaError('Invalid leagueId');
    }
    if (!isNonEmptyString(entity.driverId)) {
      throw new InvalidLeagueMembershipSchemaError('Invalid driverId');
    }
    if (!isNonEmptyString(entity.role) || !isOneOf(entity.role, VALID_ROLES)) {
      throw new InvalidLeagueMembershipSchemaError('Invalid role');
    }
    if (!isNonEmptyString(entity.status) || !isOneOf(entity.status, VALID_STATUSES)) {
      throw new InvalidLeagueMembershipSchemaError('Invalid status');
    }
    if (!(entity.joinedAt instanceof Date) || Number.isNaN(entity.joinedAt.getTime())) {
      throw new InvalidLeagueMembershipSchemaError('Invalid joinedAt');
    }

    return LeagueMembership.rehydrate({
      id: entity.id,
      leagueId: entity.leagueId,
      driverId: entity.driverId,
      role: entity.role,
      status: entity.status,
      joinedAt: entity.joinedAt,
    });
  }
}