import { GpsFixType, LocateMode, UtilityType } from '@prisma/client';
import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
  IsDateString,
  IsEnum,
  IsInt,
  IsNumber,
  IsOptional,
  IsString,
  Matches,
  Max,
  Min,
} from 'class-validator';

export class CreatePointDto {
  @ApiProperty({ minimum: -90, maximum: 90 })
  @IsNumber()
  @Min(-90)
  @Max(90)
  lat: number;

  @ApiProperty({ minimum: -180, maximum: 180 })
  @IsNumber()
  @Min(-180)
  @Max(180)
  lng: number;

  @ApiPropertyOptional({ description: 'Meters' })
  @IsOptional()
  @IsNumber()
  altitude?: number;

  @ApiPropertyOptional({ enum: GpsFixType })
  @IsOptional()
  @IsEnum(GpsFixType)
  fixType?: GpsFixType;

  @ApiPropertyOptional({ description: 'Horizontal accuracy, meters', minimum: 0 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  hAccuracy?: number;

  @ApiPropertyOptional({ description: 'Meters below grade', minimum: 0 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  depth?: number;

  @ApiPropertyOptional({ enum: UtilityType })
  @IsOptional()
  @IsEnum(UtilityType)
  utilityType?: UtilityType;

  @ApiPropertyOptional({ description: 'Ordering within a locate run' })
  @IsOptional()
  @IsInt()
  sequence?: number;

  // GPS quality
  @ApiPropertyOptional({ description: 'Vertical accuracy, meters', minimum: 0 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  vAccuracy?: number;

  @ApiPropertyOptional({ minimum: 0 })
  @IsOptional()
  @IsInt()
  @Min(0)
  satellites?: number;

  @ApiPropertyOptional({ minimum: 0 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  hdop?: number;

  // Locator receiver telemetry
  @ApiPropertyOptional({ description: 'Locate frequency, Hz', minimum: 0 })
  @IsOptional()
  @IsInt()
  @Min(0)
  frequencyHz?: number;

  @ApiPropertyOptional({ description: 'Signal current on the line, mA', minimum: 0 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  currentMa?: number;

  @ApiPropertyOptional({ description: 'Signal strength, dB' })
  @IsOptional()
  @IsNumber()
  signalDb?: number;

  @ApiPropertyOptional({ description: 'Receiver gain, dB' })
  @IsOptional()
  @IsNumber()
  gainDb?: number;

  @ApiPropertyOptional({ enum: LocateMode })
  @IsOptional()
  @IsEnum(LocateMode)
  locateMode?: LocateMode;

  @ApiPropertyOptional({ description: 'Degrees' })
  @IsOptional()
  @IsNumber()
  phaseDeg?: number;

  @ApiPropertyOptional({ description: 'Line direction, 0-360', minimum: 0, maximum: 360 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  @Max(360)
  compassDeg?: number;

  @ApiPropertyOptional({ minimum: 0, maximum: 100 })
  @IsOptional()
  @IsNumber()
  @Min(0)
  @Max(100)
  distortionPct?: number;

  @ApiProperty({ format: 'date-time', description: 'Device GPS timestamp' })
  @IsDateString()
  recordedAt: string;
}

export class QueryPointsDto {
  @ApiPropertyOptional({ format: 'date-time', description: 'Return points recorded strictly after this instant' })
  @IsOptional()
  @IsDateString()
  after?: string;

  @ApiPropertyOptional({ format: 'date-time' })
  @IsOptional()
  @IsDateString()
  from?: string;

  @ApiPropertyOptional({ format: 'date-time' })
  @IsOptional()
  @IsDateString()
  to?: string;

  @ApiPropertyOptional({ description: 'minLng,minLat,maxLng,maxLat', example: '-96.85,33.14,-96.82,33.16' })
  @IsOptional()
  @IsString()
  @Matches(/^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?$/, {
    message: 'bbox must be "minLng,minLat,maxLng,maxLat"',
  })
  bbox?: string;

  @ApiPropertyOptional({ minimum: 1, maximum: 10000, default: 5000 })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  @Max(10000)
  limit?: number;
}
