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 { ChannelsClient } from './channels.classes.client.js';
import { ChannelsConfigFlow } from './channels.classes.configflow.js';
import { createChannelsDiscoveryDescriptor } from './channels.discovery.js';
import { ChannelsMapper } from './channels.mapper.js';
import type { IChannelsConfig, IChannelsFavoriteChannel } from './channels.types.js';

export class ChannelsIntegration extends BaseIntegration<IChannelsConfig> {
  public readonly domain = 'channels';
  public readonly displayName = 'Channels';
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createChannelsDiscoveryDescriptor();
  public readonly configFlow = new ChannelsConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/channels',
    upstreamDomain: 'channels',
    iotClass: 'local_polling',
    qualityScale: 'legacy',
    requirements: ['pychannels==1.2.3'],
    dependencies: [],
    afterDependencies: [],
    codeowners: [],
    documentation: 'https://www.home-assistant.io/integrations/channels',
    configFlow: true,
    nativeRuntime: {
      polling: true,
      localHttpApi: true,
      livePush: false,
      commandRequiresHostOrExecutor: true,
    },
  };

  public async setup(configArg: IChannelsConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new ChannelsRuntime(new ChannelsClient(configArg));
  }

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

export class HomeAssistantChannelsIntegration extends ChannelsIntegration {}

class ChannelsRuntime implements IIntegrationRuntime {
  public domain = 'channels';

  constructor(private readonly client: ChannelsClient) {}

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

  public async entities(): Promise<IIntegrationEntity[]> {
    return ChannelsMapper.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 === 'channels') {
        return await this.callChannelsService(requestArg);
      }
      return { success: false, error: `Unsupported Channels 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 === 'play' || requestArg.service === 'media_play') {
      await this.client.resume();
      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.togglePause();
      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.skipForward();
      return { success: true };
    }
    if (requestArg.service === 'previous_track' || requestArg.service === 'media_previous_track') {
      await this.client.skipBackward();
      return { success: true };
    }
    if (requestArg.service === 'volume_mute') {
      const muted = this.boolData(requestArg, 'is_volume_muted') ?? this.boolData(requestArg, 'muted') ?? this.boolData(requestArg, 'mute');
      if (typeof muted !== 'boolean') {
        return { success: false, error: 'Channels volume_mute requires data.is_volume_muted.' };
      }
      await this.client.setMuted(muted);
      return { success: true };
    }
    if (requestArg.service === 'select_source') {
      const source = this.stringData(requestArg, 'source');
      if (!source) {
        return { success: false, error: 'Channels select_source requires data.source.' };
      }
      const snapshot = await this.client.getSnapshot();
      const channel = this.findFavoriteChannel(snapshot.favoriteChannels, source);
      const channelNumber = ChannelsMapper.channelNumber(channel);
      if (!channelNumber) {
        return { success: false, error: `Channels favorite channel not found: ${source}` };
      }
      await this.client.playChannel(channelNumber);
      return { success: true };
    }
    if (requestArg.service === 'play_media') {
      return await this.playMedia(requestArg);
    }
    return { success: false, error: `Unsupported Channels media_player service: ${requestArg.service}` };
  }

  private async callChannelsService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.service === 'snapshot') {
      return { success: true, data: await this.client.getSnapshot() };
    }
    if (requestArg.service === 'seek_forward') {
      await this.client.seekForward();
      return { success: true };
    }
    if (requestArg.service === 'seek_backward') {
      await this.client.seekBackward();
      return { success: true };
    }
    if (requestArg.service === 'seek_by' || requestArg.service === 'seek') {
      const seconds = this.numberData(requestArg, 'seconds') ?? this.numberData(requestArg, 'seek_position') ?? this.numberData(requestArg, 'position');
      if (typeof seconds !== 'number') {
        return { success: false, error: 'Channels seek_by requires data.seconds.' };
      }
      await this.client.seek(seconds);
      return { success: true };
    }
    if (requestArg.service === 'channel_up') {
      await this.client.channelUp();
      return { success: true };
    }
    if (requestArg.service === 'channel_down') {
      await this.client.channelDown();
      return { success: true };
    }
    if (requestArg.service === 'previous_channel') {
      await this.client.previousChannel();
      return { success: true };
    }
    if (requestArg.service === 'toggle_cc') {
      await this.client.toggleCaptions();
      return { success: true };
    }
    if (requestArg.service === 'toggle_record') {
      await this.client.toggleRecord();
      return { success: true };
    }
    if (requestArg.service === 'navigate') {
      const section = this.stringData(requestArg, 'section');
      if (!section) {
        return { success: false, error: 'Channels navigate requires data.section.' };
      }
      await this.client.navigate(section);
      return { success: true };
    }
    if (requestArg.service === 'notify') {
      const title = this.stringData(requestArg, 'title');
      const message = this.stringData(requestArg, 'message');
      if (!title || !message) {
        return { success: false, error: 'Channels notify requires data.title and data.message.' };
      }
      await this.client.notify(title, message);
      return { success: true };
    }
    return { success: false, error: `Unsupported Channels service: ${requestArg.service}` };
  }

  private async playMedia(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    const mediaType = this.stringData(requestArg, 'media_content_type') || this.stringData(requestArg, 'mediaType') || this.stringData(requestArg, 'media_type');
    const mediaId = this.stringData(requestArg, 'media_content_id') || this.stringData(requestArg, 'mediaId') || this.stringData(requestArg, 'media_id');
    if (!mediaId) {
      return { success: false, error: 'Channels play_media requires data.media_content_id.' };
    }
    if (!mediaType || mediaType === 'channel') {
      await this.client.playChannel(mediaId);
      return { success: true };
    }
    if (mediaType === 'movie' || mediaType === 'episode' || mediaType === 'tvshow' || mediaType === 'recording') {
      await this.client.playRecording(mediaId);
      return { success: true };
    }
    return { success: false, error: `Unsupported Channels media type: ${mediaType}` };
  }

  private findFavoriteChannel(channelsArg: IChannelsFavoriteChannel[], sourceArg: string): IChannelsFavoriteChannel | undefined {
    return channelsArg.find((channelArg) => ChannelsMapper.channelName(channelArg) === sourceArg || ChannelsMapper.channelNumber(channelArg) === sourceArg);
  }

  private stringData(requestArg: IServiceCallRequest, keyArg: string): string | undefined {
    const value = requestArg.data?.[keyArg];
    return typeof value === 'string' && value.trim() ? value.trim() : undefined;
  }

  private numberData(requestArg: IServiceCallRequest, keyArg: string): number | undefined {
    const value = requestArg.data?.[keyArg];
    if (typeof value === 'number' && Number.isFinite(value)) {
      return value;
    }
    if (typeof value === 'string' && value.trim()) {
      const parsed = Number(value);
      return Number.isFinite(parsed) ? parsed : undefined;
    }
    return undefined;
  }

  private boolData(requestArg: IServiceCallRequest, keyArg: string): boolean | undefined {
    const value = requestArg.data?.[keyArg];
    if (typeof value === 'boolean') {
      return value;
    }
    if (typeof value === 'string') {
      if (value.toLowerCase() === 'true') {
        return true;
      }
      if (value.toLowerCase() === 'false') {
        return false;
      }
    }
    return undefined;
  }
}
