import { MediaReference } from '@core/domain/media/MediaReference';
import { Team } from '@core/racing/domain/entities/Team';

import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';

import type { TeamJoinRequest, TeamMembership } from '@core/racing/domain/types/TeamMembership';

import { TeamJoinRequestOrmEntity, TeamMembershipOrmEntity, TeamOrmEntity } from '../entities/TeamOrmEntities';
import {
    assertArray,
    assertDate,
    assertEnumValue,
    assertNonEmptyString,
    assertOptionalStringOrNull,
} from '../schema/TypeOrmSchemaGuards';

const TEAM_ROLES = ['owner', 'manager', 'driver'] as const;
const TEAM_MEMBERSHIP_STATUSES = ['active', 'pending', 'none'] as const;

export class TeamOrmMapper {
  toOrmEntity(domain: Team): TeamOrmEntity {
    const entity = new TeamOrmEntity();
    entity.id = domain.id;
    entity.name = domain.name.toString();
    entity.tag = domain.tag.toString();
    entity.description = domain.description.toString();
    entity.ownerId = domain.ownerId.toString();
    entity.leagues = domain.leagues.map((l) => l.toString());
    entity.category = domain.category ?? null;
    entity.isRecruiting = domain.isRecruiting;
    entity.createdAt = domain.createdAt.toDate();
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    entity.logoRef = domain.logoRef.toJSON() as any;
    return entity;
  }

  toDomain(entity: TeamOrmEntity): Team {
    const entityName = 'Team';

    assertNonEmptyString(entityName, 'id', entity.id);
    assertNonEmptyString(entityName, 'name', entity.name);
    assertNonEmptyString(entityName, 'tag', entity.tag);
    assertNonEmptyString(entityName, 'description', entity.description);
    assertNonEmptyString(entityName, 'ownerId', entity.ownerId);
    assertDate(entityName, 'createdAt', entity.createdAt);

    assertArray(entityName, 'leagues', entity.leagues);
    for (const leagueId of entity.leagues) {
      assertNonEmptyString(entityName, 'leagues', leagueId);
    }

    try {
      const rehydrateProps: {
        id: string;
        name: string;
        tag: string;
        description: string;
        ownerId: string;
        leagues: string[];
        category?: string;
        isRecruiting: boolean;
        createdAt: Date;
        logoRef?: MediaReference;
      } = {
        id: entity.id,
        name: entity.name,
        tag: entity.tag,
        description: entity.description,
        ownerId: entity.ownerId,
        leagues: entity.leagues,
        isRecruiting: entity.isRecruiting ?? false,
        createdAt: entity.createdAt,
      };
      
      if (entity.category !== null && entity.category !== undefined) {
        rehydrateProps.category = entity.category;
      }
      
      if (entity.logoRef !== null && entity.logoRef !== undefined) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        rehydrateProps.logoRef = MediaReference.fromJSON(entity.logoRef as any);
      }
      
      return Team.rehydrate(rehydrateProps);
    } catch {
      throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: '__root', reason: 'invalid_shape' });
    }
  }
}

export class TeamMembershipOrmMapper {
  toOrmMembership(membership: TeamMembership): TeamMembershipOrmEntity {
    const entity = new TeamMembershipOrmEntity();
    entity.teamId = membership.teamId;
    entity.driverId = membership.driverId;
    entity.role = membership.role;
    entity.status = membership.status;
    entity.joinedAt = membership.joinedAt;
    return entity;
  }

  toDomainMembership(entity: TeamMembershipOrmEntity): TeamMembership {
    const entityName = 'TeamMembership';

    assertNonEmptyString(entityName, 'teamId', entity.teamId);
    assertNonEmptyString(entityName, 'driverId', entity.driverId);
    assertEnumValue(entityName, 'role', entity.role, TEAM_ROLES);
    assertEnumValue(entityName, 'status', entity.status, TEAM_MEMBERSHIP_STATUSES);
    assertDate(entityName, 'joinedAt', entity.joinedAt);

    return {
      teamId: entity.teamId,
      driverId: entity.driverId,
      role: entity.role,
      status: entity.status,
      joinedAt: entity.joinedAt,
    };
  }

  toOrmJoinRequest(request: TeamJoinRequest): TeamJoinRequestOrmEntity {
    const entity = new TeamJoinRequestOrmEntity();
    entity.id = request.id;
    entity.teamId = request.teamId;
    entity.driverId = request.driverId;
    entity.requestedAt = request.requestedAt;
    entity.message = request.message ?? null;
    return entity;
  }

  toDomainJoinRequest(entity: TeamJoinRequestOrmEntity): TeamJoinRequest {
    const entityName = 'TeamJoinRequest';

    assertNonEmptyString(entityName, 'id', entity.id);
    assertNonEmptyString(entityName, 'teamId', entity.teamId);
    assertNonEmptyString(entityName, 'driverId', entity.driverId);
    assertDate(entityName, 'requestedAt', entity.requestedAt);
    assertOptionalStringOrNull(entityName, 'message', entity.message);

    return {
      id: entity.id,
      teamId: entity.teamId,
      driverId: entity.driverId,
      requestedAt: entity.requestedAt,
      ...(entity.message !== null && entity.message !== undefined ? { message: entity.message } : {}),
    };
  }
}