import type {
  ConfiguredDefaultServerDefinition,
  DefaultEndpointTemplate,
  DefaultServerDefinition,
  ServerEndpoint
} from '../models/server-directory.model';

export function sanitiseServerBaseUrl(rawUrl: string): string {
  let cleaned = rawUrl.trim().replace(/\/+$/, '');

  if (cleaned.toLowerCase().endsWith('/api')) {
    cleaned = cleaned.slice(0, -4);
  }

  return cleaned;
}

export function normaliseConfiguredServerUrl(
  rawUrl: string,
  defaultProtocol: 'http' | 'https'
): string {
  let cleaned = rawUrl.trim();

  if (!cleaned) {
    return '';
  }

  if (cleaned.toLowerCase().startsWith('ws://')) {
    cleaned = `http://${cleaned.slice(5)}`;
  } else if (cleaned.toLowerCase().startsWith('wss://')) {
    cleaned = `https://${cleaned.slice(6)}`;
  } else if (cleaned.startsWith('//')) {
    cleaned = `${defaultProtocol}:${cleaned}`;
  } else if (!/^[a-z][a-z\d+.-]*:\/\//i.test(cleaned)) {
    cleaned = `${defaultProtocol}://${cleaned}`;
  }

  return sanitiseServerBaseUrl(cleaned);
}

export function buildFallbackDefaultServerUrl(
  configuredUrl: string | undefined,
  defaultProtocol: 'http' | 'https'
): string {
  if (configuredUrl?.trim()) {
    return normaliseConfiguredServerUrl(configuredUrl, defaultProtocol);
  }

  return `${defaultProtocol}://localhost:3001`;
}

export function buildDefaultServerDefinitions(
  configuredDefaults: ConfiguredDefaultServerDefinition[] | undefined,
  configuredUrl: string | undefined,
  defaultProtocol: 'http' | 'https'
): DefaultServerDefinition[] {
  const seenKeys = new Set<string>();
  const seenUrls = new Set<string>();
  const definitions = (configuredDefaults ?? [])
    .map((server, index) => {
      const key = server.key?.trim() || `default-${index + 1}`;
      const url = normaliseConfiguredServerUrl(server.url ?? '', defaultProtocol);

      if (!key || !url || seenKeys.has(key) || seenUrls.has(url)) {
        return null;
      }

      seenKeys.add(key);
      seenUrls.add(url);

      return {
        key,
        name: server.name?.trim() || (index === 0 ? 'Default Server' : `Default Server ${index + 1}`),
        url
      } satisfies DefaultServerDefinition;
    })
    .filter((definition): definition is DefaultServerDefinition => definition !== null);

  if (definitions.length > 0) {
    return definitions;
  }

  return [
    {
      key: 'default',
      name: 'Default Server',
      url: buildFallbackDefaultServerUrl(configuredUrl, defaultProtocol)
    }
  ];
}

export function buildDefaultEndpointTemplates(
  definitions: DefaultServerDefinition[]
): DefaultEndpointTemplate[] {
  return definitions.map((definition) => ({
    name: definition.name,
    url: definition.url,
    isActive: true,
    isDefault: true,
    defaultKey: definition.key,
    status: 'unknown'
  }));
}

export function hasEndpointForDefault(
  endpoints: ServerEndpoint[],
  defaultEndpoint: DefaultEndpointTemplate
): boolean {
  return endpoints.some((endpoint) =>
    endpoint.defaultKey === defaultEndpoint.defaultKey
    || sanitiseServerBaseUrl(endpoint.url) === defaultEndpoint.url
  );
}

export function matchDefaultEndpointTemplate(
  defaultEndpoints: DefaultEndpointTemplate[],
  endpoint: ServerEndpoint,
  sanitisedUrl: string,
  claimedDefaultKeys: Set<string>
): DefaultEndpointTemplate | null {
  if (endpoint.defaultKey) {
    return defaultEndpoints.find(
      (candidate) => candidate.defaultKey === endpoint.defaultKey && !claimedDefaultKeys.has(candidate.defaultKey)
    ) ?? null;
  }

  if (!endpoint.isDefault) {
    return null;
  }

  const matchingCurrentDefault = defaultEndpoints.find(
    (candidate) => candidate.url === sanitisedUrl && !claimedDefaultKeys.has(candidate.defaultKey)
  );

  if (matchingCurrentDefault) {
    return matchingCurrentDefault;
  }

  return defaultEndpoints.find(
    (candidate) => !claimedDefaultKeys.has(candidate.defaultKey)
  ) ?? null;
}

export function findDefaultEndpointKeyByUrl(
  defaultEndpoints: DefaultEndpointTemplate[],
  url: string
): string | null {
  const sanitisedUrl = sanitiseServerBaseUrl(url);

  return defaultEndpoints.find((endpoint) => endpoint.url === sanitisedUrl)?.defaultKey ?? null;
}

export function ensureAnyActiveEndpoint(endpoints: ServerEndpoint[]): ServerEndpoint[] {
  if (endpoints.length === 0 || endpoints.some((endpoint) => endpoint.isActive)) {
    return endpoints;
  }

  const nextEndpoints = [...endpoints];

  nextEndpoints[0] = {
    ...nextEndpoints[0],
    isActive: true
  };

  return nextEndpoints;
}

export function ensureCompatibleActiveEndpoint(endpoints: ServerEndpoint[]): ServerEndpoint[] {
  if (endpoints.length === 0 || endpoints.some((endpoint) => endpoint.isActive)) {
    return endpoints;
  }

  const fallbackIndex = endpoints.findIndex((endpoint) => endpoint.status !== 'incompatible');

  if (fallbackIndex < 0) {
    return endpoints;
  }

  const nextEndpoints = [...endpoints];

  nextEndpoints[fallbackIndex] = {
    ...nextEndpoints[fallbackIndex],
    isActive: true
  };

  return nextEndpoints;
}
