import { Expose, plainToClass, Type } from 'class-transformer';
import { IsDefined, IsNumber, IsOptional, IsString, IsUrl, MaxLength, MinLength, ValidateNested } from 'class-validator';
import { ValidationClass } from './validationClass';

export enum StreamIOEvent {
    RecordingReady,
    ParticipantLeft,
    ParticipantJoined,
    HLSStarted,
    CallMissed,
    CallSessionEnded,
    StatsReportReady,
}

const streamIOEventMapper: Record<string, StreamIOEvent> = {
    'call.hls_broadcasting_started': StreamIOEvent.HLSStarted,
    'call.missed': StreamIOEvent.CallMissed,
    'call.recording_ready': StreamIOEvent.RecordingReady,
    'call.session_ended': StreamIOEvent.CallSessionEnded,
    'call.session_participant_joined': StreamIOEvent.ParticipantJoined,
    'call.session_participant_left': StreamIOEvent.ParticipantLeft,
    'call.stats_report_ready': StreamIOEvent.StatsReportReady,
};

class User extends ValidationClass {
    @IsDefined()
    @IsString()
    @MinLength(1)
    @MaxLength(255)
    @Expose()
    id!: string;
}

class Member extends ValidationClass {
    @IsOptional()
    @Expose()
    @Type(() => User)
    @ValidateNested()
    user!: User;
}

class CallRecording extends ValidationClass {
    @IsDefined()
    @IsString()
    @MinLength(1)
    @MaxLength(255)
    @Expose()
    filename!: string;

    @IsDefined()
    @IsString()
    @MinLength(1)
    @MaxLength(1024)
    @Expose()
    url!: string;
}

class CallParticipant extends ValidationClass {
    @IsDefined()
    @IsString()
    @MinLength(1)
    @MaxLength(255)
    @Expose()
    role!: string;

    @IsDefined()
    @Expose()
    @Type(() => User)
    @ValidateNested()
    user!: User;
}

export class StreamIOWebhookVC extends ValidationClass {
    @IsDefined()
    @IsString()
    @MinLength(1)
    @MaxLength(255)
    @Expose()
    type!: string;

    @IsDefined()
    @IsString()
    @MinLength(1)
    @MaxLength(255)
    @Expose()
    call_cid!: string;

    @IsOptional()
    @Expose()
    @Type(() => CallRecording)
    @ValidateNested()
    call_recording?: CallRecording;

    @IsOptional()
    @Expose()
    @Type(() => CallParticipant)
    @ValidateNested()
    participant?: CallParticipant;

    @IsOptional()
    @Expose()
    @IsUrl()
    hls_playlist_url?: string;

    @IsOptional()
    @Expose()
    @Type(() => User)
    @ValidateNested()
    user?: User;

    @IsOptional()
    @Expose()
    @Type(() => Member)
    @ValidateNested()
    members?: Member[];

    @IsOptional()
    @Expose()
    @IsNumber()
    duration_seconds?: number;

    static fromObject(object: any): StreamIOWebhookVC {
        return plainToClass(StreamIOWebhookVC, object, { excludeExtraneousValues: true });
    }

    isSupportedEvent = () => Object.keys(streamIOEventMapper).includes(this.type);

    getEvent = (): StreamIOEvent => streamIOEventMapper[this.type];
}
