import type {
  AzureDevOpsOrganization,
  GitIntegrationConfig,
  GitIntegrationProvider,
  GitIntegrationSource,
  GitIntegrationSettings,
} from "./types";

export const gitIntegrationProviders: GitIntegrationProvider[] = [
  "github",
  "gitlab",
  "gitlab-self-hosted",
  "azure-devops",
  "gitea",
];

const defaults: Record<GitIntegrationProvider, Omit<GitIntegrationConfig, "provider">> = {
  github: {
    enabled: false,
    baseUrl: "https://github.com",
    username: "",
    tokenStored: false,
  },
  gitlab: {
    enabled: false,
    baseUrl: "https://gitlab.com",
    username: "",
    tokenStored: false,
  },
  "gitlab-self-hosted": {
    enabled: false,
    baseUrl: "",
    username: "",
    tokenStored: false,
  },
  "azure-devops": {
    enabled: false,
    baseUrl: "https://dev.azure.com/",
    username: "",
    tokenStored: false,
  },
  gitea: {
    enabled: false,
    baseUrl: "",
    username: "",
    tokenStored: false,
  },
};

export function defaultGitIntegrationSettings(): GitIntegrationSettings {
  return {
    providers: Object.fromEntries(
      gitIntegrationProviders.map((provider) => [provider, { provider, ...defaults[provider] }]),
    ) as GitIntegrationSettings["providers"],
    azureDevOpsOrganizations: [],
  };
}

function normaliseAzureOrganization(value: unknown): AzureDevOpsOrganization | null {
  if (!value || typeof value !== "object") return null;
  const stored = value as Partial<AzureDevOpsOrganization>;
  const id = typeof stored.id === "string" && /^[a-zA-Z0-9_-]{1,80}$/.test(stored.id) ? stored.id : "";
  if (!id) return null;
  return {
    id,
    name: typeof stored.name === "string" ? stored.name : "",
    enabled: stored.enabled === true,
    baseUrl: typeof stored.baseUrl === "string" ? stored.baseUrl : "",
    username: typeof stored.username === "string" ? stored.username : "",
    tokenStored: stored.tokenStored === true,
  };
}

export function normaliseGitIntegrationSettings(value: unknown): GitIntegrationSettings {
  const fallback = defaultGitIntegrationSettings();
  if (!value || typeof value !== "object") return fallback;
  const storedProviders = (value as Partial<GitIntegrationSettings>).providers;
  if (!storedProviders || typeof storedProviders !== "object") return fallback;

  for (const provider of gitIntegrationProviders) {
    const stored = storedProviders[provider] as Partial<GitIntegrationConfig> | undefined;
    if (!stored || typeof stored !== "object") continue;
    fallback.providers[provider] = {
      provider,
      enabled: stored.enabled === true,
      baseUrl: typeof stored.baseUrl === "string" ? stored.baseUrl : fallback.providers[provider].baseUrl,
      username: typeof stored.username === "string" ? stored.username : "",
      tokenStored: stored.tokenStored === true,
    };
  }

  const storedOrganizations = (value as Partial<GitIntegrationSettings>).azureDevOpsOrganizations;
  if (Array.isArray(storedOrganizations)) {
    const seen = new Set<string>();
    fallback.azureDevOpsOrganizations = storedOrganizations
      .map(normaliseAzureOrganization)
      .filter((organization): organization is AzureDevOpsOrganization => {
        if (!organization || seen.has(organization.id)) return false;
        seen.add(organization.id);
        return true;
      });
  } else {
    const legacy = fallback.providers["azure-devops"];
    const hasLegacyConfiguration = legacy.enabled || legacy.tokenStored || legacy.username.trim().length > 0 || !/^https:\/\/dev\.azure\.com\/?$/i.test(legacy.baseUrl.trim());
    if (hasLegacyConfiguration) {
      fallback.azureDevOpsOrganizations = [{
        id: "default",
        name: "Azure DevOps",
        enabled: legacy.enabled,
        baseUrl: legacy.baseUrl,
        username: legacy.username,
        tokenStored: legacy.tokenStored,
      }];
    }
  }
  return fallback;
}

export function integrationCredentialKey(provider: GitIntegrationProvider, accountId?: string): string {
  if (provider === "azure-devops" && accountId && accountId !== "default") {
    return `integration:${provider}:${accountId}`;
  }
  return `integration:${provider}`;
}

export function configuredIntegrationSources(settings: GitIntegrationSettings): GitIntegrationSource[] {
  const sources: GitIntegrationSource[] = [];
  for (const provider of gitIntegrationProviders) {
    if (provider === "azure-devops") continue;
    const config = settings.providers[provider];
    if (config.enabled && config.tokenStored && config.baseUrl.trim()) {
      sources.push({ id: provider, provider, label: providerLabel(provider), baseUrl: config.baseUrl });
    }
  }
  for (const organization of settings.azureDevOpsOrganizations) {
    if (!organization.enabled || !organization.tokenStored || !organization.baseUrl.trim()) continue;
    sources.push({
      id: `azure-devops:${organization.id}`,
      provider: "azure-devops",
      accountId: organization.id,
      label: organization.name.trim() || organizationNameFromUrl(organization.baseUrl) || "Azure DevOps",
      baseUrl: organization.baseUrl,
    });
  }
  return sources;
}

export function configuredIntegrationCount(settings: GitIntegrationSettings): number {
  return configuredIntegrationSources(settings).length;
}

export function providerLabel(provider: GitIntegrationProvider): string {
  return {
    github: "GitHub",
    gitlab: "GitLab.com",
    "gitlab-self-hosted": "GitLab Self-Managed",
    "azure-devops": "Azure DevOps",
    gitea: "Gitea",
  }[provider];
}

export function organizationNameFromUrl(value: string): string {
  try {
    const url = new URL(value);
    return url.pathname.split("/").filter(Boolean)[0] ?? "";
  } catch {
    return "";
  }
}
