package export

import (
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
)

// ToGlobalExport converts OpenAPI Export to global Export (for CreateExport request body).
func ToGlobalExport(o *openapingv1beta2.Export, createdBy string) *globalngv1.Export {
	if o == nil {
		return nil
	}
	return &globalngv1.Export{
		DisplayName:   o.DisplayName,
		TidbId:        o.TidbId,
		ExportOptions: toGlobalExportOptionsFull(o.ExportOptions),
		CloudStorage:  toGlobalCloudStorage(o.CloudStorage),
		Username:      o.Username,
		Password:      o.Password,
		ExportId:      o.ExportId,
		CreatedBy:     createdBy,
		State:         globalngv1.Export_State(o.State),
		Reason:        o.Reason,
		SnapshotTso:   o.SnapshotTso,
		SnapshotTime:  o.SnapshotTime,
		CreateTime:    o.CreateTime,
		UpdateTime:    o.UpdateTime,
		CompleteTime:  o.CompleteTime,
	}
}

// ToOpenAPIExport converts global Export to OpenAPI Export (for responses).
func ToOpenAPIExport(g *globalngv1.Export) *openapingv1beta2.Export {
	if g == nil {
		return nil
	}
	return &openapingv1beta2.Export{
		ExportId:      g.ExportId,
		DisplayName:   g.DisplayName,
		TidbId:        g.TidbId,
		CreatedBy:     common.ConvCreatedBy(g.CreatedBy),
		State:         openapingv1beta2.Export_State(g.State),
		ExportOptions: toOpenAPIExportOptions(g.ExportOptions),
		CloudStorage:  toOpenAPICloudStorage(g.CloudStorage),
		Reason:        g.Reason,
		SnapshotTso:   g.SnapshotTso,
		SnapshotTime:  g.SnapshotTime,
		Username:      g.Username,
		CreateTime:    g.CreateTime,
		UpdateTime:    g.UpdateTime,
		CompleteTime:  g.CompleteTime,
	}
}

func toGlobalExportOptionsFull(o *openapingv1beta2.ExportOptions) *globalngv1.ExportOptions {
	if o == nil {
		return nil
	}
	out := &globalngv1.ExportOptions{
		FileType:    globalngv1.ExportOptions_FileType(o.FileType),
		Compression: globalngv1.ExportOptions_CompressionType(o.Compression),
		CsvFormat:   toGlobalCSVFormat(o.CsvFormat),
	}
	if o.Filter != nil {
		if tbl := toGlobalFilterTypeTable(o.Filter); tbl != nil {
			out.Filter = &globalngv1.ExportOptions_Filter{Type: tbl}
		} else if sql := toGlobalFilterTypeSql(o.Filter); sql != nil {
			out.Filter = &globalngv1.ExportOptions_Filter{Type: sql}
		}
	}
	return out
}

func toGlobalFilterTypeSql(o *openapingv1beta2.ExportOptions_Filter) *globalngv1.ExportOptions_Filter_Sql {
	if o == nil {
		return nil
	}
	if t, ok := o.Type.(*openapingv1beta2.ExportOptions_Filter_Sql); ok && t != nil {
		return &globalngv1.ExportOptions_Filter_Sql{Sql: t.Sql}
	}
	return nil
}

func toGlobalFilterTypeTable(o *openapingv1beta2.ExportOptions_Filter) *globalngv1.ExportOptions_Filter_Table_ {
	if o == nil {
		return nil
	}
	if t, ok := o.Type.(*openapingv1beta2.ExportOptions_Filter_Table_); ok && t != nil && t.Table != nil {
		return &globalngv1.ExportOptions_Filter_Table_{Table: &globalngv1.ExportOptions_Filter_Table{
			Patterns: t.Table.Patterns,
			Where:    t.Table.Where,
		}}
	}
	return nil
}

func toGlobalCSVFormat(o *openapingv1beta2.ExportOptions_CSVFormat) *globalngv1.ExportOptions_CSVFormat {
	if o == nil {
		return nil
	}
	return &globalngv1.ExportOptions_CSVFormat{
		Separator:  o.Separator,
		Delimiter:  o.Delimiter,
		NullValue:  o.NullValue,
		SkipHeader: o.SkipHeader,
	}
}

func toOpenAPIExportOptions(g *globalngv1.ExportOptions) *openapingv1beta2.ExportOptions {
	if g == nil {
		return nil
	}
	out := &openapingv1beta2.ExportOptions{
		FileType:    openapingv1beta2.ExportOptions_FileType(g.FileType),
		Compression: openapingv1beta2.ExportOptions_CompressionType(g.Compression),
		CsvFormat:   toOpenAPICSVFormat(g.CsvFormat),
	}
	if g.Filter != nil {
		out.Filter = toOpenAPIFilter(g.Filter)
	}
	return out
}

func toOpenAPIFilter(g *globalngv1.ExportOptions_Filter) *openapingv1beta2.ExportOptions_Filter {
	if g == nil {
		return nil
	}
	switch t := g.Type.(type) {
	case *globalngv1.ExportOptions_Filter_Sql:
		if t != nil {
			return &openapingv1beta2.ExportOptions_Filter{Type: &openapingv1beta2.ExportOptions_Filter_Sql{Sql: t.Sql}}
		}
	case *globalngv1.ExportOptions_Filter_Table_:
		if t != nil && t.Table != nil {
			return &openapingv1beta2.ExportOptions_Filter{
				Type: &openapingv1beta2.ExportOptions_Filter_Table_{Table: &openapingv1beta2.ExportOptions_Filter_Table{
					Patterns: t.Table.Patterns,
					Where:    t.Table.Where,
				}},
			}
		}
	}
	return nil
}

func toOpenAPICSVFormat(g *globalngv1.ExportOptions_CSVFormat) *openapingv1beta2.ExportOptions_CSVFormat {
	if g == nil {
		return nil
	}
	return &openapingv1beta2.ExportOptions_CSVFormat{
		Separator:  g.Separator,
		Delimiter:  g.Delimiter,
		NullValue:  g.NullValue,
		SkipHeader: g.SkipHeader,
	}
}

func toGlobalCloudStorage(o *openapingv1beta2.CloudStorage) *globalngv1.CloudStorage {
	if o == nil {
		return nil
	}
	out := &globalngv1.CloudStorage{
		Type: globalngv1.CloudStorageType_Enum(o.Type),
	}
	if v := o.GetS3(); v != nil {
		out.Storage = &globalngv1.CloudStorage_S3{
			S3: toGlobalS3(v),
		}
	} else if v := o.GetGcs(); v != nil {
		out.Storage = &globalngv1.CloudStorage_Gcs{Gcs: toGlobalGCS(v)}
	} else if v := o.GetAzureBlob(); v != nil {
		out.Storage = &globalngv1.CloudStorage_AzureBlob{AzureBlob: toGlobalAzureBlob(v)}
	} else if v := o.GetOss(); v != nil {
		out.Storage = &globalngv1.CloudStorage_Oss{Oss: toGlobalOSS(v)}
	}
	return out
}

func toGlobalS3(o *openapingv1beta2.S3CloudStorage) *globalngv1.S3CloudStorage {
	if o == nil {
		return nil
	}
	out := &globalngv1.S3CloudStorage{
		Uri:      o.Uri,
		AuthType: globalngv1.S3CloudStorage_S3AuthType(o.AuthType),
	}
	if v := o.GetAccessKey(); v != nil {
		out.Auth = &globalngv1.S3CloudStorage_AccessKey_{AccessKey: &globalngv1.S3CloudStorage_AccessKey{Id: v.Id, Secret: v.Secret}}
	} else if v := o.GetRoleArn(); v != "" {
		out.Auth = &globalngv1.S3CloudStorage_RoleArn{RoleArn: v}
	}
	return out
}

func toGlobalGCS(o *openapingv1beta2.GCSCloudStorage) *globalngv1.GCSCloudStorage {
	if o == nil {
		return nil
	}
	out := &globalngv1.GCSCloudStorage{
		Uri:      o.Uri,
		AuthType: globalngv1.GCSCloudStorage_GCSAuthType(o.AuthType),
	}
	if v := o.GetServiceAccountKey(); v != "" {
		out.Auth = &globalngv1.GCSCloudStorage_ServiceAccountKey{ServiceAccountKey: v}
	}
	return out
}

func toGlobalAzureBlob(o *openapingv1beta2.AzureBlobCloudStorage) *globalngv1.AzureBlobCloudStorage {
	if o == nil {
		return nil
	}
	out := &globalngv1.AzureBlobCloudStorage{
		Uri:      o.Uri,
		AuthType: globalngv1.AzureBlobCloudStorage_AzureBlobAuthType(o.AuthType),
	}
	if v := o.GetSasToken(); v != "" {
		out.Auth = &globalngv1.AzureBlobCloudStorage_SasToken{SasToken: v}
	}
	return out
}

func toGlobalOSS(o *openapingv1beta2.OSSCloudStorage) *globalngv1.OSSCloudStorage {
	if o == nil {
		return nil
	}
	out := &globalngv1.OSSCloudStorage{
		Uri:      o.Uri,
		AuthType: globalngv1.OSSCloudStorage_OSSAuthType(o.AuthType),
	}
	if v := o.GetAccessKey(); v != nil {
		out.Auth = &globalngv1.OSSCloudStorage_AccessKey_{AccessKey: &globalngv1.OSSCloudStorage_AccessKey{Id: v.Id, Secret: v.Secret}}
	} else if v := o.GetRoleArn(); v != "" {
		out.Auth = &globalngv1.OSSCloudStorage_RoleArn{RoleArn: v}
	}
	return out
}

func toOpenAPICloudStorage(g *globalngv1.CloudStorage) *openapingv1beta2.CloudStorage {
	if g == nil {
		return nil
	}
	out := &openapingv1beta2.CloudStorage{
		Type: openapingv1beta2.CloudStorageType_Enum(g.Type),
	}
	if v := g.GetS3(); v != nil {
		out.Storage = &openapingv1beta2.CloudStorage_S3{S3: toOpenAPIS3(v)}
	} else if v := g.GetGcs(); v != nil {
		out.Storage = &openapingv1beta2.CloudStorage_Gcs{Gcs: toOpenAPIGCS(v)}
	} else if v := g.GetAzureBlob(); v != nil {
		out.Storage = &openapingv1beta2.CloudStorage_AzureBlob{AzureBlob: toOpenAPIAzureBlob(v)}
	} else if v := g.GetOss(); v != nil {
		out.Storage = &openapingv1beta2.CloudStorage_Oss{Oss: toOpenAPIOSS(v)}
	}
	return out
}

func toOpenAPIS3(g *globalngv1.S3CloudStorage) *openapingv1beta2.S3CloudStorage {
	if g == nil {
		return nil
	}
	out := &openapingv1beta2.S3CloudStorage{Uri: g.Uri, AuthType: openapingv1beta2.S3CloudStorage_S3AuthType(g.AuthType)}
	if v := g.GetAccessKey(); v != nil {
		out.Auth = &openapingv1beta2.S3CloudStorage_AccessKey_{AccessKey: &openapingv1beta2.S3CloudStorage_AccessKey{Id: v.Id, Secret: v.Secret}}
	} else if v := g.GetRoleArn(); v != "" {
		out.Auth = &openapingv1beta2.S3CloudStorage_RoleArn{RoleArn: v}
	}
	return out
}

func toOpenAPIGCS(g *globalngv1.GCSCloudStorage) *openapingv1beta2.GCSCloudStorage {
	if g == nil {
		return nil
	}
	out := &openapingv1beta2.GCSCloudStorage{Uri: g.Uri, AuthType: openapingv1beta2.GCSCloudStorage_GCSAuthType(g.AuthType)}
	if t, ok := g.Auth.(*globalngv1.GCSCloudStorage_ServiceAccountKey); ok && t != nil {
		out.Auth = &openapingv1beta2.GCSCloudStorage_ServiceAccountKey{ServiceAccountKey: t.ServiceAccountKey}
	}
	return out
}

func toOpenAPIAzureBlob(g *globalngv1.AzureBlobCloudStorage) *openapingv1beta2.AzureBlobCloudStorage {
	if g == nil {
		return nil
	}
	out := &openapingv1beta2.AzureBlobCloudStorage{Uri: g.Uri, AuthType: openapingv1beta2.AzureBlobCloudStorage_AzureBlobAuthType(g.AuthType)}
	if v := g.GetSasToken(); v != "" {
		out.Auth = &openapingv1beta2.AzureBlobCloudStorage_SasToken{SasToken: v}
	}
	return out
}

func toOpenAPIOSS(g *globalngv1.OSSCloudStorage) *openapingv1beta2.OSSCloudStorage {
	if g == nil {
		return nil
	}
	out := &openapingv1beta2.OSSCloudStorage{Uri: g.Uri, AuthType: openapingv1beta2.OSSCloudStorage_OSSAuthType(g.AuthType)}
	if v := g.GetAccessKey(); v != nil {
		out.Auth = &openapingv1beta2.OSSCloudStorage_AccessKey_{AccessKey: &openapingv1beta2.OSSCloudStorage_AccessKey{Id: v.Id, Secret: v.Secret}}
	} else if v := g.GetRoleArn(); v != "" {
		out.Auth = &openapingv1beta2.OSSCloudStorage_RoleArn{RoleArn: v}
	}
	return out
}
