export const linkplayDefaultPort = 80;
export const linkplayDefaultTimeoutMs = 5000;

export type TLinkplayProtocol = 'http' | 'https';
export type TLinkplaySnapshotSource = 'snapshot' | 'http' | 'executor' | 'manual' | 'runtime';
export type TLinkplayPlayingStatus = 'play' | 'pause' | 'stop' | 'load' | (string & {});
export type TLinkplayRepeatMode = 'off' | 'one' | 'all';
export type TLinkplayCommand =
  | 'play'
  | 'pause'
  | 'stop'
  | 'next_track'
  | 'previous_track'
  | 'play_media'
  | 'seek'
  | 'set_volume'
  | 'mute'
  | 'select_source'
  | 'set_repeat'
  | 'set_sound_mode'
  | 'play_preset'
  | 'timesync'
  | 'restart'
  | 'set_audio_output_hardware_mode'
  | 'join'
  | 'unjoin'
  | 'group_volume_set'
  | 'group_mute'
  | 'raw_command';

export type TLinkplayPlayingMode =
  | '-96'
  | '-1'
  | '0'
  | '1'
  | '2'
  | '3'
  | '10'
  | '11'
  | '12'
  | '13'
  | '14'
  | '16'
  | '19'
  | '20'
  | '21'
  | '29'
  | '30'
  | '31'
  | '32'
  | '36'
  | '40'
  | '41'
  | '43'
  | '44'
  | '45'
  | '46'
  | '47'
  | '48'
  | '49'
  | '50'
  | '51'
  | '52'
  | '53'
  | '54'
  | '56'
  | '57'
  | '58'
  | '60'
  | '99'
  | (string & {});

export type TLinkplayLoopMode = '-1' | '0' | '1' | '2' | '3' | '4' | '5' | (string & {});
export type TLinkplayAudioOutputHardwareMode = 'optical' | 'line_out' | 'coaxial' | 'headphones' | (string & {});

export interface ILinkplayConfig {
  host?: string;
  port?: number;
  protocol?: TLinkplayProtocol;
  timeoutMs?: number;
  name?: string;
  uniqueId?: string;
  manufacturer?: string;
  model?: string;
  modelId?: string;
  macAddress?: string;
  snapshot?: ILinkplaySnapshot;
  commandExecutor?: ILinkplayCommandExecutor;
}

export interface IHomeAssistantLinkplayConfig extends ILinkplayConfig {}

export interface ILinkplayCommandExecutor {
  execute(requestArg: ILinkplayRawCommandRequest): Promise<ILinkplayCommandExecutorResult | unknown>;
}

export interface ILinkplayRawCommandRequest {
  command: string;
  url?: string;
  host?: string;
  port: number;
  protocol: TLinkplayProtocol;
  expectJson?: boolean;
  speakerUuid?: string;
  speakerName?: string;
}

export interface ILinkplayCommandExecutorResult {
  ok?: boolean;
  success?: boolean;
  status?: number;
  response?: string;
  data?: unknown;
}

export interface ILinkplayCommandRequest {
  command: TLinkplayCommand;
  speakerUuid?: string;
  source?: string;
  mediaId?: string;
  mediaType?: string;
  url?: string;
  volumeLevel?: number;
  volume?: number;
  muted?: boolean;
  repeat?: TLinkplayRepeatMode;
  soundMode?: string;
  preset?: number;
  position?: number;
  groupMemberUuids?: string[];
  hardwareMode?: TLinkplayAudioOutputHardwareMode | string;
  rawCommand?: string;
}

export interface ILinkplayDeviceProperties {
  uuid?: string;
  DeviceName?: string;
  GroupName?: string;
  firmware?: string;
  hardware?: string;
  project?: string;
  MAC?: string;
  STA_MAC?: string;
  ETH_MAC?: string;
  eth2?: string;
  eth0?: string;
  apcli0?: string;
  plm_support?: string;
  preset_key?: string;
  [key: string]: unknown;
}

export interface ILinkplayPlayerProperties {
  type?: string;
  ch?: string;
  mode?: TLinkplayPlayingMode;
  loop?: TLinkplayLoopMode;
  eq?: string;
  status?: TLinkplayPlayingStatus;
  curpos?: string | number;
  offset_pts?: string | number;
  totlen?: string | number;
  Title?: string;
  Artist?: string;
  Album?: string;
  plicount?: string | number;
  plicurr?: string | number;
  vol?: string | number;
  mute?: string | number;
  [key: string]: unknown;
}

export interface ILinkplayMetaInfo {
  metaData?: {
    album?: string;
    title?: string;
    subtitle?: string;
    albumArtURI?: string;
    sampleRate?: string | number;
    bitDepth?: string | number;
    bitRate?: string | number;
    trackId?: string;
    [key: string]: unknown;
  };
  [key: string]: unknown;
}

export interface ILinkplayDeviceInfo {
  uuid: string;
  name: string;
  host?: string;
  port?: number;
  protocol?: TLinkplayProtocol;
  endpoint?: string;
  manufacturer?: string;
  model?: string;
  modelId?: string;
  project?: string;
  macAddress?: string;
  hardwareVersion?: string;
  firmwareVersion?: string;
  ethernetAddress?: string;
  playModeSupport?: TLinkplayPlayingMode[];
  maxPresets?: number;
  properties?: ILinkplayDeviceProperties;
}

export interface ILinkplayPlayerStatus {
  status: TLinkplayPlayingStatus;
  playMode?: TLinkplayPlayingMode;
  loopMode?: TLinkplayLoopMode;
  equalizerMode?: string;
  volume?: number;
  muted?: boolean;
  title?: string;
  artist?: string;
  album?: string;
  albumArtUrl?: string;
  currentPositionMs?: number;
  totalLengthMs?: number;
  source?: string;
  speakerType?: string;
  channelType?: string;
  properties?: ILinkplayPlayerProperties;
  metaInfo?: ILinkplayMetaInfo;
}

export interface ILinkplaySource {
  mode: TLinkplayPlayingMode;
  name: string;
  commandValue?: string;
  available?: boolean;
}

export interface ILinkplayPreset {
  number: number;
  name?: string;
  source?: string;
}

export interface ILinkplaySpeaker {
  uuid: string;
  name?: string;
  device: ILinkplayDeviceInfo;
  player: ILinkplayPlayerStatus;
  available?: boolean;
  audioOutputHardwareMode?: TLinkplayAudioOutputHardwareMode | string;
  sources?: ILinkplaySource[];
  presets?: ILinkplayPreset[];
}

export interface ILinkplayMultiroomGroup {
  id: string;
  name?: string;
  leaderUuid: string;
  followerUuids: string[];
  volume?: number;
  muted?: boolean;
}

export interface ILinkplaySnapshot {
  speakers: ILinkplaySpeaker[];
  multirooms?: ILinkplayMultiroomGroup[];
  sources?: ILinkplaySource[];
  presets?: ILinkplayPreset[];
  online: boolean;
  updatedAt?: string;
  source?: TLinkplaySnapshotSource;
  error?: string;
  raw?: Record<string, unknown>;
}

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

export interface ILinkplaySsdpRecord {
  st?: string;
  usn?: string;
  location?: string;
  headers?: Record<string, string | undefined>;
  upnp?: Record<string, string | undefined>;
}

export interface ILinkplayManualEntry {
  host?: string;
  port?: number;
  protocol?: TLinkplayProtocol;
  id?: string;
  uuid?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  modelId?: string;
  project?: string;
  macAddress?: string;
  metadata?: Record<string, unknown>;
}

export const linkplaySourceMap: Record<string, string> = {
  '10': 'Wifi',
  '40': 'Line In',
  '41': 'Bluetooth',
  '43': 'Optical',
  '47': 'Line In 2',
  '51': 'USB DAC',
  '45': 'Coaxial',
  '48': 'XLR',
  '49': 'HDMI',
  '56': 'Optical 2',
  '53': 'External Bluetooth',
  '54': 'Phono',
  '58': 'ARC',
  '57': 'Coaxial 2',
  '16': 'SD Card 1',
  '52': 'SD Card 2',
  '50': 'CD',
  '-96': 'DAB Radio',
  '46': 'FM Radio',
  '44': 'RCA',
  '21': 'USB',
  '31': 'Spotify',
  '32': 'Tidal',
  '99': 'Follower',
};

export const linkplayPlayModeSendMap: Record<string, string> = {
  '0': 'Idle',
  '1': 'Airplay',
  '2': 'DLNA',
  '3': 'QPlay',
  '10': 'wifi',
  '11': 'udisk',
  '16': 'TFcard',
  '20': 'API',
  '21': 'udisk',
  '30': 'Alarm',
  '31': 'Spotify',
  '32': 'Tidal',
  '36': 'Qobuz',
  '40': 'line-in',
  '41': 'bluetooth',
  '43': 'optical',
  '44': 'RCA',
  '45': 'co-axial',
  '46': 'FM',
  '47': 'line-in2',
  '48': 'XLR',
  '49': 'HDMI',
  '50': 'cd',
  '51': 'PCUSB',
  '52': 'TFcard',
  '60': 'Talk',
  '99': 'Idle',
  '56': 'optical2',
  '54': 'phono',
  '57': 'co-axial2',
  '58': 'ARC',
  '-96': 'DAB',
  '53': 'extern_bluetooth',
};

export const linkplayRepeatToLoopMode: Record<TLinkplayRepeatMode, TLinkplayLoopMode> = {
  one: '-1',
  off: '4',
  all: '5',
};

export const linkplayLoopModeToRepeat: Record<string, TLinkplayRepeatMode> = {
  '-1': 'one',
  '0': 'off',
  '1': 'all',
  '2': 'all',
  '3': 'all',
  '4': 'off',
  '5': 'all',
};

export const linkplayNormalEqualizerModeToNumber: Record<string, string> = {
  None: '0',
  Classic: '1',
  Pop: '2',
  Jazz: '3',
  Vocal: '4',
};

export const linkplayNormalEqualizerNumberToMode: Record<string, string> = {
  '0': 'None',
  '1': 'Classic',
  '2': 'Pop',
  '3': 'Jazz',
  '4': 'Vocal',
};

export const linkplayAudioOutputHardwareModeToCode: Record<string, string> = {
  optical: '1',
  line_out: '2',
  coaxial: '3',
  headphones: '4',
};

export const linkplayAudioOutputHardwareCodeToMode: Record<string, TLinkplayAudioOutputHardwareMode> = {
  '1': 'optical',
  '2': 'line_out',
  '3': 'coaxial',
  '4': 'headphones',
};

export const linkplayProjectLookup: Record<string, { manufacturer: string; model: string }> = {
  SMART_ZONE4_AMP: { manufacturer: 'ArtSound', model: 'Smart Zone 4 AMP' },
  SMART_HYDE: { manufacturer: 'ArtSound', model: 'Smart Hyde' },
  ARYLIC_S50: { manufacturer: 'Arylic', model: 'S50+' },
  RP0016_S50PRO_S: { manufacturer: 'Arylic', model: 'S50 Pro' },
  RP0011_WB60_S: { manufacturer: 'Arylic', model: 'A30' },
  'X-50': { manufacturer: 'Arylic', model: 'A50' },
  ARYLIC_A50S: { manufacturer: 'Arylic', model: 'A50+' },
  RP0011_WB60: { manufacturer: 'Arylic', model: 'Up2Stream Amp 2.0' },
  UP2STREAM_AMP_V3: { manufacturer: 'Arylic', model: 'Up2Stream Amp v3' },
  UP2STREAM_AMP_V4: { manufacturer: 'Arylic', model: 'Up2Stream Amp v4' },
  UP2STREAM_PRO_V3: { manufacturer: 'Arylic', model: 'Up2Stream Pro v3' },
  UP2STREAM_PRO_V4: { manufacturer: 'Arylic', model: 'Up2Stream Pro v4' },
  S10P_WIFI: { manufacturer: 'Arylic', model: 'Arylic S10+' },
  ARYLIC_V20: { manufacturer: 'Arylic', model: 'Up2Stream Plate Amp' },
  UP2STREAM_MINI_V3: { manufacturer: 'Arylic', model: 'Up2Stream Mini' },
  UP2STREAM_AMP_2P1: { manufacturer: 'Arylic', model: 'Up2Stream Amp 2.1' },
  'iEAST-02': { manufacturer: 'iEAST', model: 'AudioCast M5' },
  WiiM_Amp_4layer: { manufacturer: 'WiiM', model: 'WiiM Amp' },
  WiiM_Pro_with_gc4a: { manufacturer: 'WiiM', model: 'WiiM Pro' },
  WiiM_Pro_Plus: { manufacturer: 'WiiM', model: 'WiiM Pro Plus' },
  WiiM_AMP: { manufacturer: 'WiiM', model: 'WiiM Amp' },
  Muzo_Mini: { manufacturer: 'WiiM', model: 'WiiM Mini' },
  GGMM_E2A: { manufacturer: 'GGMM', model: 'GGMM E2' },
  A16: { manufacturer: 'Medion', model: 'Life P66970 (MD 43970)' },
};
