package api

import (
	"fmt"
	"strconv"
	"time"

	"github.com/pingcap/dbaas/admin/forms"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/dbaas/central/model"
	"github.com/pingcap/dbaas/central/model/admin"
	"github.com/tidbcloud/idl/pbgen/proto/core"
)

func buildAPITenantUserItem(user *admin.TenantUser) forms.TenantUser {
	return forms.TenantUser{
		ID:        user.Id,
		OrgID:     user.OrgId,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Roles:     user.Roles,
		Status:    user.Status,
		Role:      user.Role,
	}
}

func buildInternalTenantUser(user *forms.TenantUser) *admin.TenantUser {
	return &admin.TenantUser{
		Id:        user.ID,
		OrgId:     user.OrgID,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Status:    user.Status,
		Roles:     user.Roles,
		Role:      user.Role,
	}
}

func buildAPITenantClusterItem(item *core.Cluster, project *entity.Project) forms.TenantCluster {
	out := forms.TenantCluster{
		ID:       int64(item.Id),
		Name:     item.Name,
		Provider: item.CloudProviderName,
		Region:   item.RegionName,
		//Profile:          item.Profile,
		Version:                  item.Version,
		Status:                   item.Status.String(),
		CreateTime:               uint64(item.CreatedAt),
		TenantComponents:         forms.TenantComponents{}, // fill later
		ProjectID:                int64(item.ProjectId),
		ProjectName:              project.Name,
		IsDevTier:                item.IsDevTier,
		CrossAccountDeploymentID: item.XaccountDeployId,
	}
	for _, component := range item.Components {
		componentItem := buildAPITenantComponent(component)

		switch component.ComponentType {
		case core.ComponentType_COMPONENT_TYPE_PD:
			out.TenantComponents.PD = componentItem
		case core.ComponentType_COMPONENT_TYPE_TIDB:
			out.TenantComponents.TiDB = componentItem
		case core.ComponentType_COMPONENT_TYPE_TIKV:
			out.TenantComponents.TiKV = componentItem
		case core.ComponentType_COMPONENT_TYPE_TIFLASH:
			out.TenantComponents.TiFlash = componentItem
		default:
			panic(fmt.Sprintf("unsupported component type, tp=%s", component.ComponentType))
		}
	}

	return out
}

func buildAPITenantComponent(component *core.ClusterComponent) forms.TenantComponent {
	return forms.TenantComponent{
		Replicas: uint32(component.Replicas),
		NodeProfile: forms.NodeProfileOfComponent{
			Compute: forms.NodeProfileCompute{
				CpuNum:   int(component.CpuNum),
				MemoryMi: int(component.MemoryGi),
			},
			StorageGi:     int(component.StorageSizeGi),
			NodeProfileID: component.NodeProfileId,
			Name:          component.NodeProfileName,
		},
		MachineType: component.ComputeInstanceType,
	}
}

func buildAPIDashboardLink(name, link string) forms.DashboardLink {
	return forms.DashboardLink{Name: name, Link: link}
}

func buildInternalCentralUser(user forms.CentralUser) *admin.CentralUser {
	return &admin.CentralUser{
		Id:        user.ID,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Roles:     user.Roles,
	}
}

func buildAPICentralUserItem(user *admin.CentralUser) forms.CentralUser {
	return forms.CentralUser{
		ID:        user.Id,
		Email:     user.Email,
		FirstName: user.FirstName,
		LastName:  user.LastName,
		Roles:     user.Roles,
	}
}

func buildAPIRoleItem(role *admin.Role) forms.Role {
	var privileges []forms.Privilege
	for _, item := range role.Privileges {
		privileges = append(privileges, forms.Privilege{
			Resource:  item.Resource,
			Operation: item.Operation,
		})
	}
	return forms.Role{
		ID:         role.Id,
		Name:       role.Name,
		Privileges: privileges,
	}
}

func buildInternalRole(role forms.Role) *admin.Role {
	var privileges []admin.Privilege
	for _, item := range role.Privileges {
		privileges = append(privileges, admin.Privilege{
			Resource:  item.Resource,
			Operation: item.Operation,
		})
	}
	return &admin.Role{
		Id:         role.ID,
		Name:       role.Name,
		Privileges: privileges,
	}
}

func buildAPITenantItem(item *admin.Tenant) forms.Tenant {
	return forms.Tenant{
		ID:                        item.ID.Uint64(),
		Name:                      item.Name,
		Alias:                     item.Alias,
		Email:                     item.Email,
		Timezone:                  item.Timezone,
		Status:                    item.Status,
		Plan:                      item.Plan,
		DiscountDescription:       item.DiscountDescription,
		Discount:                  item.Discount,
		Country:                   item.Country,
		HasDiscount:               item.HasDiscount,
		TotalCredit:               item.TotalCredit,
		RemainingCredit:           item.RemainingCredit,
		CreatedAt:                 item.CreateAt.Unix(),
		Kind:                      item.Kind,
		AccountManager:            item.AccountManager,
		ThirdPartyAccountProvider: item.ThirdPartyAccountProvider,
		ThirdPartyAccountCode:     item.ThirdPartyAccountCode,
	}
}

func buildAPIAccessLog(item model.AccessLog) forms.AccessLog {
	return forms.AccessLog{
		ID:         item.ID,
		HappenedOn: item.HappenedOn,
		User:       item.User,
		Content:    item.Content,
	}
}

func buildAPICentralUserProfile(item *admin.CentralUserProfile) forms.CentralUserProfile {
	return forms.CentralUserProfile{
		ID:    item.Id,
		Email: item.Email,
		Name:  item.Name,
		Roles: item.Roles,
	}
}

func buildAPIKey(item string) forms.CreateAPIKeyResp {
	return forms.CreateAPIKeyResp{
		APIKey: item,
	}
}

const (
	RegionDefaultBackupTimeFormat = "15:04"
)

func validateBackupTime(backupTime string) error {
	_, err := time.Parse(RegionDefaultBackupTimeFormat, backupTime)
	return err
}

func buildInternalRegion(region forms.ProviderRegion) (*admin.Region, error) {
	var openedOrgIDs []uint64
	for _, orgID := range region.OpenedOrgIDs {
		id, err := strconv.ParseUint(orgID, 10, 64)
		if err != nil {
			return nil, err
		}
		openedOrgIDs = append(openedOrgIDs, id)
	}

	err := validateBackupTime(region.DefaultBackupTime)
	if err != nil {
		return nil, err
	}

	return &admin.Region{
		Id:                region.ID,
		Provider:          region.Provider,
		Name:              region.Name,
		DisplayName:       region.DisplayName,
		Status:            region.Status,
		Zones:             region.Zones,
		IsPublic:          region.IsPublic,
		OpenedOrgIDs:      openedOrgIDs,
		DefaultBackupTime: region.DefaultBackupTime,
	}, nil
}

func buildAPIRegionItem(item *admin.Region) forms.ProviderRegion {
	var openedOrgIDs []string
	for _, orgID := range item.OpenedOrgIDs {
		openedOrgIDs = append(openedOrgIDs, strconv.FormatUint(orgID, 10))
	}
	return forms.ProviderRegion{
		ID:                item.Id,
		Provider:          item.Provider,
		Status:            item.Status,
		Zones:             item.Zones,
		Name:              item.Name,
		DisplayName:       item.DisplayName,
		IsPublic:          item.IsPublic,
		OpenedOrgIDs:      openedOrgIDs,
		DefaultBackupTime: item.DefaultBackupTime,
	}
}

func buildInternalSystemSettings(s forms.SystemSettings) *admin.SystemSettings {
	return &admin.SystemSettings{
		EnableDevTier: admin.EnableDevTier{
			EnableOnAws: s.EnableDevTier.EnableOnAws,
			EnableOnGcp: s.EnableDevTier.EnableOnGcp,
		},
	}
}

func buildSystemSettings(settings *admin.SystemSettings) forms.SystemSettings {
	return forms.SystemSettings{
		EnableDevTier: forms.EnableDevTier{
			EnableOnAws: settings.EnableDevTier.EnableOnAws,
			EnableOnGcp: settings.EnableDevTier.EnableOnGcp,
		},
	}
}

func buildDashboardStats(stats *admin.DashboardStats) forms.GetDashboardStatsResq {
	return forms.GetDashboardStatsResq{
		DevTier: forms.DevTierStats{
			AwsActiveClustersCount: stats.DevTier.AwsActiveClustersCount,
			GcpActiveClustersCount: stats.DevTier.GcpActiveClustersCount,
		},
	}
}
