import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IDlnaDmsConfig } from './dlna_dms.types.js';
import { dlnaDmsDefaultPort } from './dlna_dms.types.js';

export class DlnaDmsConfigFlow implements IConfigFlow<IDlnaDmsConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IDlnaDmsConfig>> {
    void contextArg;
    const location = this.locationFromCandidate(candidateArg);
    if ((candidateArg.source === 'ssdp' || candidateArg.source === 'manual') && location) {
      return {
        kind: 'done',
        title: candidateArg.name || 'DLNA DMS configured',
        config: this.configFromCandidate(candidateArg, location),
      };
    }

    return {
      kind: 'form',
      title: 'Manual DLNA DMS server connection',
      description: 'Enter the URL of the media server device description XML file.',
      fields: [
        { name: 'url', label: 'Description URL', type: 'text', required: true },
        { name: 'name', label: 'Name', type: 'text' },
      ],
      submit: async (valuesArg) => {
        const url = this.stringValue(valuesArg.url);
        if (!url || !this.isUrl(url)) {
          return { kind: 'error', title: 'Invalid DLNA DMS configuration', error: 'A valid description URL is required.' };
        }
        const name = this.stringValue(valuesArg.name) || candidateArg.name;
        return {
          kind: 'done',
          title: name || 'DLNA DMS configured',
          config: {
            ...this.configFromCandidate({ ...candidateArg, name }, url),
            url,
            location: url,
          },
        };
      },
    };
  }

  private configFromCandidate(candidateArg: IDiscoveryCandidate, locationArg: string): IDlnaDmsConfig {
    const metadata = candidateArg.metadata || {};
    return {
      location: locationArg,
      url: locationArg,
      deviceId: candidateArg.id,
      udn: this.stringMetadata(metadata, 'udn') || candidateArg.id?.split('::')[0],
      deviceType: this.stringMetadata(metadata, 'deviceType'),
      sourceId: this.slug(candidateArg.name || candidateArg.id || 'dlna_dms'),
      name: candidateArg.name,
      manufacturer: candidateArg.manufacturer,
      model: candidateArg.model,
      timeoutMs: 10000,
    };
  }

  private locationFromCandidate(candidateArg: IDiscoveryCandidate): string | undefined {
    const metadata = candidateArg.metadata || {};
    const explicitLocation = this.stringMetadata(metadata, 'location') || this.stringMetadata(metadata, 'url');
    if (explicitLocation) {
      return explicitLocation;
    }
    if (!candidateArg.host) {
      return undefined;
    }
    const path = this.stringMetadata(metadata, 'path') || '/description.xml';
    return `http://${candidateArg.host}:${candidateArg.port || dlnaDmsDefaultPort}${path.startsWith('/') ? path : `/${path}`}`;
  }

  private stringMetadata(metadataArg: Record<string, unknown>, keyArg: string): string | undefined {
    const value = metadataArg[keyArg];
    return typeof value === 'string' && value.trim() ? value.trim() : undefined;
  }

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

  private isUrl(valueArg: string): boolean {
    try {
      const url = new URL(valueArg);
      return url.protocol === 'http:' || url.protocol === 'https:';
    } catch {
      return false;
    }
  }

  private slug(valueArg: string): string {
    return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'dlna_dms';
  }
}
