import type * as shxInterfaces from '@smarthome.exchange/interfaces';
import { BaseIntegration } from '../../core/classes.baseintegration.js';
import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
import { KodiClient } from './kodi.classes.client.js';
import { KodiConfigFlow } from './kodi.classes.configflow.js';
import { createKodiDiscoveryDescriptor } from './kodi.discovery.js';
import { KodiMapper } from './kodi.mapper.js';
import type { IKodiConfig, TKodiMediaType } from './kodi.types.js';

export class KodiIntegration extends BaseIntegration<IKodiConfig> {
  public readonly domain = 'kodi';
  public readonly displayName = 'Kodi';
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createKodiDiscoveryDescriptor();
  public readonly configFlow = new KodiConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/kodi',
    upstreamDomain: 'kodi',
    integrationType: 'service',
    iotClass: 'local_push',
    requirements: ['pykodi==0.2.7'],
    dependencies: [],
    afterDependencies: ['media_source'],
    codeowners: ['@OnFreund'],
    configFlow: true,
    documentation: 'https://www.home-assistant.io/integrations/kodi',
  };

  public async setup(configArg: IKodiConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new KodiRuntime(new KodiClient(configArg));
  }

  public async destroy(): Promise<void> {}
}

export class HomeAssistantKodiIntegration extends KodiIntegration {}

class KodiRuntime implements IIntegrationRuntime {
  public domain = 'kodi';

  constructor(private readonly client: KodiClient) {}

  public async devices(): Promise<shxInterfaces.data.IDeviceDefinition[]> {
    return KodiMapper.toDevices(await this.client.getSnapshot());
  }

  public async entities(): Promise<IIntegrationEntity[]> {
    return KodiMapper.toEntities(await this.client.getSnapshot());
  }

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    try {
      if (requestArg.domain === 'media_player') {
        return await this.callMediaPlayerService(requestArg);
      }
      if (requestArg.domain === 'kodi') {
        return await this.callKodiService(requestArg);
      }
      if (requestArg.domain === 'notify') {
        return await this.callNotifyService(requestArg);
      }
      if (requestArg.domain === 'remote') {
        return await this.callRemoteService(requestArg);
      }
      return { success: false, error: `Unsupported Kodi service domain: ${requestArg.domain}` };
    } catch (errorArg) {
      return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
    }
  }

  public async destroy(): Promise<void> {
    await this.client.destroy();
  }

  private async callMediaPlayerService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service === 'turn_on') {
      return { success: true, data: { event: 'kodi.turn_on', entityId: requestArg.target.entityId } };
    }
    if (requestArg.service === 'turn_off') {
      await this.client.quit();
      return { success: true };
    }
    if (requestArg.service === 'play' || requestArg.service === 'media_play') {
      await this.client.play();
      return { success: true };
    }
    if (requestArg.service === 'pause' || requestArg.service === 'media_pause') {
      await this.client.pause();
      return { success: true };
    }
    if (requestArg.service === 'play_pause' || requestArg.service === 'media_play_pause') {
      await this.client.playPause();
      return { success: true };
    }
    if (requestArg.service === 'stop' || requestArg.service === 'media_stop') {
      await this.client.stop();
      return { success: true };
    }
    if (requestArg.service === 'next_track' || requestArg.service === 'media_next_track') {
      await this.client.nextTrack();
      return { success: true };
    }
    if (requestArg.service === 'previous_track' || requestArg.service === 'media_previous_track') {
      await this.client.previousTrack();
      return { success: true };
    }
    if (requestArg.service === 'seek' || requestArg.service === 'media_seek') {
      const position = requestArg.data?.seek_position ?? requestArg.data?.position;
      if (typeof position !== 'number') {
        return { success: false, error: 'Kodi seek requires data.seek_position.' };
      }
      await this.client.seek(position);
      return { success: true };
    }
    if (requestArg.service === 'volume_set') {
      const level = requestArg.data?.volume_level;
      if (typeof level !== 'number') {
        return { success: false, error: 'Kodi volume_set requires data.volume_level.' };
      }
      await this.client.setVolumeLevel(level);
      return { success: true };
    }
    if (requestArg.service === 'volume_up' || requestArg.service === 'volume_down') {
      await this.client.stepVolume(requestArg.service === 'volume_up' ? 'increment' : 'decrement');
      return { success: true };
    }
    if (requestArg.service === 'volume_mute') {
      const muted = requestArg.data?.is_volume_muted ?? requestArg.data?.muted;
      if (typeof muted !== 'boolean') {
        return { success: false, error: 'Kodi volume_mute requires data.is_volume_muted.' };
      }
      await this.client.setMuted(muted);
      return { success: true };
    }
    if (requestArg.service === 'play_media') {
      const mediaId = requestArg.data?.media_content_id ?? requestArg.data?.uri;
      const mediaType = requestArg.data?.media_content_type ?? requestArg.data?.media_type ?? 'file';
      if ((typeof mediaId !== 'string' && typeof mediaId !== 'number') || mediaId === '') {
        return { success: false, error: 'Kodi play_media requires data.media_content_id or data.uri.' };
      }
      await this.client.playMedia(typeof mediaType === 'string' ? mediaType : 'file', mediaId);
      return { success: true };
    }
    return { success: false, error: `Unsupported Kodi media_player service: ${requestArg.service}` };
  }

  private async callKodiService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service === 'call_method') {
      const method = requestArg.data?.method;
      if (typeof method !== 'string' || !method) {
        return { success: false, error: 'Kodi call_method requires data.method.' };
      }
      const params = this.callMethodParams(requestArg);
      return { success: true, data: await this.client.callMethod(method, params) };
    }
    if (requestArg.service === 'add_to_playlist') {
      const mediaType = requestArg.data?.media_type;
      const mediaId = requestArg.data?.media_id;
      if (typeof mediaType !== 'string' || (typeof mediaId !== 'string' && typeof mediaId !== 'number')) {
        return { success: false, error: 'Kodi add_to_playlist requires data.media_type and data.media_id.' };
      }
      await this.client.addToPlaylist(mediaType as TKodiMediaType, mediaId);
      return { success: true };
    }
    if (requestArg.service === 'show_notification') {
      return this.callNotifyService(requestArg);
    }
    return { success: false, error: `Unsupported Kodi service: ${requestArg.service}` };
  }

  private async callNotifyService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    const message = requestArg.data?.message;
    if (typeof message !== 'string') {
      return { success: false, error: 'Kodi notification requires data.message.' };
    }
    const title = typeof requestArg.data?.title === 'string' ? requestArg.data.title : 'Home Assistant';
    const icon = typeof requestArg.data?.icon === 'string' ? requestArg.data.icon : 'info';
    const displayTime = typeof requestArg.data?.displaytime === 'number' ? requestArg.data.displaytime : 10000;
    await this.client.showNotification(title, message, icon, displayTime);
    return { success: true };
  }

  private async callRemoteService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service !== 'send_command') {
      return { success: false, error: `Unsupported Kodi remote service: ${requestArg.service}` };
    }
    const command = requestArg.data?.command;
    const commands = typeof command === 'string' ? [command] : Array.isArray(command) ? command.filter((itemArg): itemArg is string => typeof itemArg === 'string') : [];
    if (!commands.length) {
      return { success: false, error: 'Kodi remote.send_command requires data.command.' };
    }
    for (const item of commands) {
      await this.client.input(item);
    }
    return { success: true };
  }

  private callMethodParams(requestArg: IServiceCallRequest): Record<string, unknown> | unknown[] | undefined {
    const explicitParams = requestArg.data?.params;
    if (Array.isArray(explicitParams)) {
      return explicitParams;
    }
    if (explicitParams && typeof explicitParams === 'object') {
      return explicitParams as Record<string, unknown>;
    }
    const params: Record<string, unknown> = {};
    for (const [key, value] of Object.entries(requestArg.data || {})) {
      if (key !== 'method') {
        params[key] = value;
      }
    }
    return Object.keys(params).length ? params : undefined;
  }
}
