using System;
using System.IO.Abstractions;
using StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest.Configuration;

namespace StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest.Authentication;

public sealed record CosignKeylessIdentity(
    string Issuer,
    string Subject,
    Uri? FulcioUrl,
    Uri? RekorUrl,
    string? ClientId,
    string? ClientSecret,
    string? Audience,
    string? IdentityToken);

public sealed record CosignKeyPairIdentity(
    string PrivateKeyPath,
    string? Password,
    string? CertificatePath,
    Uri? RekorUrl,
    string? FulcioRootPath);

public sealed record OciCosignAuthority(
    CosignCredentialMode Mode,
    CosignKeylessIdentity? Keyless,
    CosignKeyPairIdentity? KeyPair,
    bool RequireSignature,
    TimeSpan VerifyTimeout);

public static class OciCosignAuthorityFactory
{
    public static OciCosignAuthority Create(OciCosignVerificationOptions options, IFileSystem? fileSystem = null)
    {
        ArgumentNullException.ThrowIfNull(options);

        CosignKeylessIdentity? keyless = null;
        CosignKeyPairIdentity? keyPair = null;

        switch (options.Mode)
        {
            case CosignCredentialMode.None:
                break;

            case CosignCredentialMode.Keyless:
                keyless = CreateKeyless(options.Keyless);
                break;

            case CosignCredentialMode.KeyPair:
                keyPair = CreateKeyPair(options.KeyPair, fileSystem);
                break;

            default:
                throw new InvalidOperationException($"Unsupported Cosign credential mode '{options.Mode}'.");
        }

        return new OciCosignAuthority(
            Mode: options.Mode,
            Keyless: keyless,
            KeyPair: keyPair,
            RequireSignature: options.RequireSignature,
            VerifyTimeout: options.VerifyTimeout);
    }

    private static CosignKeylessIdentity CreateKeyless(CosignKeylessOptions options)
    {
        ArgumentNullException.ThrowIfNull(options);

        Uri? fulcio = null;
        Uri? rekor = null;

        if (!string.IsNullOrWhiteSpace(options.FulcioUrl))
        {
            fulcio = new Uri(options.FulcioUrl, UriKind.Absolute);
        }

        if (!string.IsNullOrWhiteSpace(options.RekorUrl))
        {
            rekor = new Uri(options.RekorUrl, UriKind.Absolute);
        }

        return new CosignKeylessIdentity(
            Issuer: options.Issuer!,
            Subject: options.Subject!,
            FulcioUrl: fulcio,
            RekorUrl: rekor,
            ClientId: options.ClientId,
            ClientSecret: options.ClientSecret,
            Audience: options.Audience,
            IdentityToken: options.IdentityToken);
    }

    private static CosignKeyPairIdentity CreateKeyPair(CosignKeyPairOptions options, IFileSystem? fileSystem)
    {
        ArgumentNullException.ThrowIfNull(options);

        Uri? rekor = null;
        if (!string.IsNullOrWhiteSpace(options.RekorUrl))
        {
            rekor = new Uri(options.RekorUrl, UriKind.Absolute);
        }

        return new CosignKeyPairIdentity(
            PrivateKeyPath: options.PrivateKeyPath!,
            Password: options.Password,
            CertificatePath: options.CertificatePath,
            RekorUrl: rekor,
            FulcioRootPath: options.FulcioRootPath);
    }
}
