import * as plugins from '../../plugins.js';
import { BaseIntegration } from '../../core/classes.baseintegration.js';
import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
import { AndroidtvClient } from './androidtv.classes.client.js';
import { AndroidtvConfigFlow } from './androidtv.classes.configflow.js';
import { createAndroidtvDiscoveryDescriptor } from './androidtv.discovery.js';
import { AndroidtvMapper } from './androidtv.mapper.js';
import type { IAndroidtvConfig } from './androidtv.types.js';

export class AndroidtvIntegration extends BaseIntegration<IAndroidtvConfig> {
  public readonly domain = 'androidtv';
  public readonly displayName = 'Android Debug Bridge';
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createAndroidtvDiscoveryDescriptor();
  public readonly configFlow = new AndroidtvConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/androidtv',
    upstreamDomain: 'androidtv',
    integrationType: 'device',
    iotClass: 'local_polling',
    requirements: ['adb-shell[async]==0.4.4', 'androidtv[async]==0.0.75'],
    dependencies: [],
    afterDependencies: [],
    codeowners: ['@JeffLIrion', '@ollo69'],
  };

  public async setup(configArg: IAndroidtvConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new AndroidtvRuntime(new AndroidtvClient(configArg));
  }

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

export class HomeAssistantAndroidtvIntegration extends AndroidtvIntegration {}

class AndroidtvRuntime implements IIntegrationRuntime {
  public domain = 'androidtv';

  constructor(private readonly client: AndroidtvClient) {}

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

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

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

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

  private async callRemoteService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service !== 'send_command') {
      return { success: false, error: `Unsupported Android TV 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: 'Android TV remote.send_command requires data.command.' };
    }
    const repeats = typeof requestArg.data?.num_repeats === 'number' ? requestArg.data.num_repeats : 1;
    await this.client.sendCommand(commands, repeats);
    return { success: true };
  }

  private async callAndroidtvService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service === 'adb_command') {
      const command = requestArg.data?.command;
      if (typeof command !== 'string' || !command) {
        return { success: false, error: 'Android TV adb_command requires data.command.' };
      }
      await this.client.adbCommand(command);
      return { success: true };
    }
    return { success: false, error: `Unsupported Android TV service: ${requestArg.service}` };
  }

  private async callMediaPlayerService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service === 'turn_on') {
      await this.client.turnOn();
      return { success: true };
    }
    if (requestArg.service === 'turn_off') {
      await this.client.turnOff();
      return { success: true };
    }
    if (requestArg.service === 'play' || requestArg.service === 'media_play') {
      await this.client.mediaPlay();
      return { success: true };
    }
    if (requestArg.service === 'pause' || requestArg.service === 'media_pause') {
      await this.client.mediaPause();
      return { success: true };
    }
    if (requestArg.service === 'play_pause' || requestArg.service === 'media_play_pause') {
      await this.client.mediaPlayPause();
      return { success: true };
    }
    if (requestArg.service === 'stop' || requestArg.service === 'media_stop') {
      await this.client.mediaStop();
      return { success: true };
    }
    if (requestArg.service === 'volume_set') {
      const level = requestArg.data?.volume_level;
      if (typeof level !== 'number') {
        return { success: false, error: 'Android TV 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' ? 1 : -1);
      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: 'Android TV volume_mute requires data.is_volume_muted.' };
      }
      await this.client.muteVolume(muted);
      return { success: true };
    }
    if (requestArg.service === 'select_source') {
      const source = requestArg.data?.source;
      if (typeof source !== 'string' || !source) {
        return { success: false, error: 'Android TV select_source requires data.source.' };
      }
      await this.client.selectSource(source);
      return { success: true };
    }
    return { success: false, error: `Unsupported Android TV media_player service: ${requestArg.service}` };
  }
}
