import {
  IsOptional,
  IsString,
  IsUUID,
  IsNumber,
  IsArray,
  IsIn,
  MaxLength,
  Min,
  IsEnum,
  ValidateNested,
  Matches,
} from 'class-validator';
import {
  DOCUMENT_URL_PATTERN,
  DOCUMENT_URL_MESSAGE,
} from '../../../common/validation/document-url';
import { Type, Transform } from 'class-transformer';
import { OpStatus } from '../../../common/constants/op-status';
import { TICKET_STATUS_VALUES } from '../../../common/constants/ticket-status';
import { ItemSupplierInputDto } from './supplier-input.dto';

/**
 * PatchActivityItemDto — partial update used by the Movement Chart
 * Planner tab for per-row autosave on blur. Unlike
 * UpdateBookingActivityItemDto (which is embedded inside the whole-
 * booking update), every field here is optional — ops edits one cell
 * at a time.
 */
export class PatchActivityItemDto {
  @IsUUID() @IsOptional() supplier_id?: string | null;
  @IsString() @IsOptional() @MaxLength(255) supplier_name_text?: string | null;
  @IsString() @IsOptional() @MaxLength(20) supplier_phone_text?: string | null;
  @IsString() @IsOptional() @MaxLength(100) slot?: string | null;
  @IsString() @IsOptional() @MaxLength(1000) notes?: string | null;
  @IsNumber() @IsOptional() @Min(0) quantity?: number;
  @IsNumber() @IsOptional() unit_price?: number;
  @IsNumber() @IsOptional() subtotal?: number;
  @IsUUID() @IsOptional() ticket_id?: string | null;
  @IsString() @IsOptional() @MaxLength(20) assignment_status?: string | null;
  @IsOptional() @IsIn(TICKET_STATUS_VALUES) ticket_status?: string;
  @IsString()
  @IsOptional()
  @MaxLength(500)
  @Matches(DOCUMENT_URL_PATTERN, { message: DOCUMENT_URL_MESSAGE })
  @Transform(({ value }) => (value === '' ? undefined : value))
  ticket_file_url?: string | null;

  // Per-row pax override (partial cancellation). Null clears the
  // override; omitted ⇒ unchanged.
  @IsNumber() @IsOptional() @Min(0) adults_override?: number | null;
  @IsNumber() @IsOptional() @Min(0) children_override?: number | null;
  /** Confirmed charge (selling currency) for pax ADDED beyond the
   *  booking's own count on this line. Required when add-on pax go up;
   *  never 0 — add-ons are always billed (client rule 2026-10-15). */
  @IsNumber() @IsOptional() @Min(0.01) addon_charge?: number;

  // Operational status. Activities can't go to DISPATCHED but enum
  // validation is shared — service guards against illegal transitions.
  @IsEnum(OpStatus) @IsOptional() op_status?: OpStatus;

  // Per-line ACTUAL supplier cost — what we owe the supplier for this
  // logical Planner row (fan-out: applied to every age_group sibling).
  // Drives the SUPPLIER REFUND amount when a supplier is assigned.
  @IsNumber() @IsOptional() @Min(0) actual_supplier_cost?: number | null;

  /** Multi-supplier assignment — see AssignTransportItemDto for the
   *  Phase 3 semantics. */
  @IsArray()
  @IsOptional()
  @ValidateNested({ each: true })
  @Type(() => ItemSupplierInputDto)
  suppliers?: ItemSupplierInputDto[];
}

/**
 * Bulk supplier-assign for activity items — selected in the Planner
 * Activity view, one supplier applied to all. Driver/vehicle don't
 * apply to activities; hence this DTO is narrower than the transport
 * bulk-assign counterpart.
 */
export class BulkPatchActivityItemDto {
  @IsArray()
  @IsUUID('4', { each: true })
  item_ids: string[];

  @IsUUID() @IsOptional() supplier_id?: string | null;
  @IsString() @IsOptional() @MaxLength(255) supplier_name_text?: string | null;
  @IsString() @IsOptional() @MaxLength(20) supplier_phone_text?: string | null;
}
