import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IAndroidIpWebcamConfig, TAndroidIpWebcamProtocol } from './android_ip_webcam.types.js';
import { androidIpWebcamDefaultPort, androidIpWebcamDefaultTimeoutMs } from './android_ip_webcam.types.js';

export class AndroidIpWebcamConfigFlow implements IConfigFlow<IAndroidIpWebcamConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IAndroidIpWebcamConfig>> {
    void contextArg;
    return {
      kind: 'form',
      title: 'Connect Android IP Webcam',
      description: 'Configure the local Android IP Webcam HTTP endpoint. Use either a base URL such as http://192.168.1.20:8080 or host plus port.',
      fields: [
        { name: 'url', label: 'Base URL', type: 'text' },
        { name: 'host', label: 'Host', type: 'text' },
        { name: 'port', label: 'Port', type: 'number' },
        { name: 'username', label: 'Username', type: 'text' },
        { name: 'password', label: 'Password', type: 'password' },
        { name: 'name', label: 'Name', type: 'text' },
      ],
      submit: async (valuesArg) => {
        const urlValue = this.stringValue(valuesArg.url) || this.stringMetadata(candidateArg, 'url');
        const endpoint = this.endpoint(urlValue, this.stringValue(valuesArg.host) || candidateArg.host, this.numberValue(valuesArg.port) || candidateArg.port, this.protocolMetadata(candidateArg));
        if (!endpoint.host) {
          return { kind: 'error', error: 'Android IP Webcam requires a base URL or host.' };
        }
        const username = this.stringValue(valuesArg.username) || this.stringMetadata(candidateArg, 'username');
        const password = this.stringValue(valuesArg.password) || this.stringMetadata(candidateArg, 'password');
        if ((username && password === undefined) || (!username && password !== undefined)) {
          return { kind: 'error', error: 'Android IP Webcam username and password must be provided together.' };
        }

        return {
          kind: 'done',
          title: 'Android IP Webcam configured',
          config: {
            protocol: endpoint.protocol,
            host: endpoint.host,
            port: endpoint.port,
            url: endpoint.url,
            username,
            password,
            name: this.stringValue(valuesArg.name) || candidateArg.name || endpoint.host,
            uniqueId: candidateArg.id || endpoint.host,
            manufacturer: candidateArg.manufacturer || 'Android IP Webcam',
            model: candidateArg.model,
            timeoutMs: androidIpWebcamDefaultTimeoutMs,
          },
        };
      },
    };
  }

  private endpoint(urlArg: string | undefined, hostArg: string | undefined, portArg: number | undefined, protocolArg: TAndroidIpWebcamProtocol | undefined): { protocol: TAndroidIpWebcamProtocol; host?: string; port: number; url?: string } {
    const url = safeUrl(urlArg || hostArg);
    if (url) {
      const protocol = url.protocol === 'https:' ? 'https' : 'http';
      const port = url.port ? Number(url.port) : protocol === 'https' ? 443 : androidIpWebcamDefaultPort;
      return { protocol, host: url.hostname, port, url: url.toString().replace(/\/$/, '') };
    }
    const protocol = protocolArg || 'http';
    const port = portArg || androidIpWebcamDefaultPort;
    return { protocol, host: hostArg, port, url: hostArg ? `${protocol}://${hostArg}:${port}` : undefined };
  }

  private stringValue(valueArg: unknown): string | undefined {
    return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
  }

  private numberValue(valueArg: unknown): number | undefined {
    if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
      return valueArg;
    }
    if (typeof valueArg === 'string' && valueArg.trim()) {
      const value = Number(valueArg);
      return Number.isFinite(value) ? value : undefined;
    }
    return undefined;
  }

  private stringMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): string | undefined {
    const value = candidateArg.metadata?.[keyArg];
    return typeof value === 'string' && value.trim() ? value.trim() : undefined;
  }

  private protocolMetadata(candidateArg: IDiscoveryCandidate): TAndroidIpWebcamProtocol | undefined {
    const protocol = candidateArg.metadata?.protocol;
    return protocol === 'http' || protocol === 'https' ? protocol : undefined;
  }
}

const safeUrl = (valueArg: string | undefined): URL | undefined => {
  if (!valueArg) {
    return undefined;
  }
  try {
    return new URL(valueArg);
  } catch {
    return undefined;
  }
};
