export const plexDefaultPort = 32400;

export type TPlexSnapshotSource = 'manual' | 'http' | 'runtime';
export type TPlexDiscoveryProtocol = 'manual' | 'gdm' | 'mdns' | 'ssdp' | 'zeroconf';
export type TPlexPlayerState = 'playing' | 'paused' | 'stopped' | 'buffering' | 'idle' | 'offline' | (string & {});
export type TPlexMediaContentType = 'movie' | 'tvshow' | 'episode' | 'music' | 'track' | 'album' | 'artist' | 'photo' | 'video' | 'clip' | (string & {});
export type TPlexPlaybackCommand =
  | 'play'
  | 'pause'
  | 'stop'
  | 'skipNext'
  | 'skipPrevious'
  | 'seekTo'
  | 'setParameters'
  | 'playMedia'
  | (string & {});

export interface IPlexConfig {
  host?: string;
  port?: number;
  ssl?: boolean;
  verifySsl?: boolean;
  url?: string;
  token?: string;
  timeoutMs?: number;
  name?: string;
  serverIdentifier?: string;
  clientIdentifier?: string;
  ignorePlexWebClients?: boolean;
  snapshot?: IPlexSnapshot;
  server?: IPlexServerInfo;
  clients?: IPlexClientInfo[];
  sessions?: IPlexSession[];
  libraries?: IPlexLibrarySection[];
}

export interface IHomeAssistantPlexConfig extends IPlexConfig {}

export interface IPlexServerInfo {
  machineIdentifier?: string;
  friendlyName?: string;
  name?: string;
  version?: string;
  platform?: string;
  platformVersion?: string;
  url?: string;
  host?: string;
  port?: number;
  ssl?: boolean;
  claimed?: boolean;
  myPlex?: boolean;
  myPlexUsername?: string;
  allowSync?: boolean;
  allowSharing?: boolean;
  allowMediaDeletion?: boolean;
  transcoderActiveVideoSessions?: number;
  updatedAt?: number | string;
  online?: boolean;
  [key: string]: unknown;
}

export interface IPlexClientInfo {
  machineIdentifier?: string;
  id?: string;
  host?: string;
  address?: string;
  port?: number;
  baseUrl?: string;
  name?: string;
  title?: string;
  product?: string;
  platform?: string;
  platformVersion?: string;
  device?: string;
  deviceClass?: string;
  model?: string;
  vendor?: string;
  version?: string;
  protocol?: string;
  protocolCapabilities?: string[];
  state?: TPlexPlayerState;
  local?: boolean;
  relayed?: boolean;
  secure?: boolean;
  transient?: boolean;
  source?: 'PMS' | 'GDM' | 'plex.tv' | 'session' | 'manual' | (string & {});
  volumeLevel?: number;
  muted?: boolean;
  [key: string]: unknown;
}

export interface IPlexSessionUser {
  id?: string | number;
  title?: string;
  username?: string;
  thumb?: string;
}

export interface IPlexSessionTransport {
  bandwidth?: number;
  id?: string;
  location?: 'lan' | 'wan' | string;
}

export interface IPlexMediaStream {
  id?: string | number;
  streamType?: number;
  codec?: string;
  displayTitle?: string;
  language?: string;
  selected?: boolean;
  [key: string]: unknown;
}

export interface IPlexMediaPart {
  id?: string | number;
  key?: string;
  file?: string;
  duration?: number;
  size?: number;
  container?: string;
  Stream?: IPlexMediaStream[];
  [key: string]: unknown;
}

export interface IPlexMediaItem {
  ratingKey?: string | number;
  key?: string;
  guid?: string;
  title?: string;
  type?: TPlexMediaContentType;
  summary?: string;
  contentRating?: string;
  librarySectionID?: string | number;
  librarySectionTitle?: string;
  grandparentTitle?: string;
  parentTitle?: string;
  grandparentThumb?: string;
  parentThumb?: string;
  thumb?: string;
  art?: string;
  duration?: number;
  viewOffset?: number;
  year?: number;
  index?: number;
  parentIndex?: number;
  originalTitle?: string;
  Media?: Array<{
    id?: string | number;
    duration?: number;
    videoResolution?: string;
    audioCodec?: string;
    videoCodec?: string;
    Part?: IPlexMediaPart[];
    [key: string]: unknown;
  }>;
  [key: string]: unknown;
}

export interface IPlexSession extends IPlexMediaItem {
  sessionKey?: string | number;
  state?: TPlexPlayerState;
  Player?: IPlexClientInfo;
  Session?: IPlexSessionTransport;
  User?: IPlexSessionUser;
  username?: string;
  players?: IPlexClientInfo[];
  mediaPositionUpdatedAt?: string;
}

export interface IPlexLibrarySection {
  key: string | number;
  uuid?: string;
  title?: string;
  type?: TPlexMediaContentType;
  agent?: string;
  scanner?: string;
  language?: string;
  allowSync?: boolean;
  refreshing?: boolean;
  thumb?: string;
  art?: string;
  composite?: string;
  contentChangedAt?: number;
  createdAt?: number;
  scannedAt?: number;
  updatedAt?: number;
  totalSize?: number;
  itemCount?: number;
  leafCount?: number;
  counts?: Record<string, number | undefined>;
  lastAddedItem?: string;
  lastAddedTimestamp?: string | number;
  Location?: Array<{ id?: number | string; path?: string }>;
  [key: string]: unknown;
}

export interface IPlexSnapshot {
  server: IPlexServerInfo;
  clients: IPlexClientInfo[];
  sessions: IPlexSession[];
  libraries: IPlexLibrarySection[];
  capturedAt?: string;
  source?: TPlexSnapshotSource;
  online?: boolean;
  events?: IPlexEvent[];
}

export interface IPlexPlaybackCommand {
  clientIdentifier: string;
  command: TPlexPlaybackCommand;
  mediaType?: 'video' | 'music' | 'photo' | string;
  offsetMs?: number;
  volume?: number;
  muted?: boolean;
  params?: Record<string, string | number | boolean | undefined>;
}

export interface IPlexPlayMediaCommand extends IPlexPlaybackCommand {
  command: 'playMedia';
  key: string;
  containerKey?: string;
  machineIdentifier?: string;
  address?: string;
  port?: number;
  protocol?: 'http' | 'https' | string;
  token?: string;
}

export interface IPlexRefreshLibraryCommand {
  libraryName?: string;
  libraryKey?: string | number;
  force?: boolean;
  path?: string;
}

export interface IPlexCommandResult {
  success: boolean;
  error?: string;
  data?: unknown;
}

export type TPlexEventType = 'snapshot' | 'command' | 'library_refresh' | 'error';

export interface IPlexEvent {
  type: TPlexEventType;
  timestamp: number;
  serverId?: string;
  clientIdentifier?: string;
  entityId?: string;
  command?: IPlexPlaybackCommand | IPlexRefreshLibraryCommand;
  data?: unknown;
}

export interface IPlexMediaContainer<TDirectory = unknown, TMetadata = unknown> {
  MediaContainer?: {
    Directory?: TDirectory[];
    Metadata?: TMetadata[];
    Server?: IPlexClientInfo[];
    size?: number;
    totalSize?: number;
    machineIdentifier?: string;
    friendlyName?: string;
    version?: string;
    claimed?: boolean;
    [key: string]: unknown;
  };
}

export interface IPlexGdmRecord {
  data?: Record<string, string | undefined>;
  from?: [string, number] | { address?: string; port?: number };
  host?: string;
  port?: number;
}

export interface IPlexMdnsRecord {
  name?: string;
  type?: string;
  serviceType?: string;
  host?: string;
  hostname?: string;
  port?: number;
  addresses?: string[];
  txt?: Record<string, string | undefined>;
  properties?: Record<string, string | undefined>;
}

export interface IPlexSsdpRecord {
  headers?: Record<string, string | undefined>;
  st?: string;
  usn?: string;
  location?: string;
  server?: string;
  friendlyName?: string;
  manufacturer?: string;
  modelName?: string;
  host?: string;
  port?: number;
  metadata?: Record<string, unknown>;
}

export interface IPlexManualEntry {
  host?: string;
  port?: number;
  ssl?: boolean;
  verifySsl?: boolean;
  url?: string;
  token?: string;
  id?: string;
  serverIdentifier?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  snapshot?: IPlexSnapshot;
  metadata?: Record<string, unknown>;
}

export interface IPlexGdmDiscoveryEntry {
  source: 'gdm';
  contentType?: string;
  host?: string;
  port?: number;
  name?: string;
  resourceIdentifier?: string;
  version?: string;
  product?: string;
  protocolCapabilities?: string[];
  raw?: IPlexGdmRecord;
}
