package converter

import (
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/service/skills"
	store "github.com/tidbcloud/AgentTeam/internal/store/resource/skills"
)

func ToSkill(v store.Skill) dto.Skill {
	return ToSkillWithRepositories(v, skills.SkillRepositories{})
}

func ToSkillWithRepositories(v store.Skill, repositories skills.SkillRepositories) dto.Skill {
	primary := ToResourceRepositoryRef(repositories.Primary)
	return dto.Skill{
		ID:                v.ID,
		WorkspaceID:       v.WorkspaceID,
		Slug:              v.Slug,
		Name:              v.Name,
		Description:       v.Description,
		StorageScope:      v.StorageScope,
		StorageOwnerLogin: v.StorageOwnerLogin,
		VisibilityScope:   v.VisibilityScope,
		VisibilityOwnerID: v.VisibilityOwnerID,
		SkillCount:        v.SkillCount,
		IsActive:          v.IsActive,
		IsOfficial:        skills.IsOfficialBuiltinSkill(v),
		Repositories:      dto.SkillRepositories{Primary: primary},
		Role:              v.Role,
		CanManage:         v.CanManage,
		CreatedBy:         v.CreatedBy,
		UpdatedBy:         v.UpdatedBy,
		CreatedAt:         v.CreatedAt.UTC().Format(timeLayout),
		UpdatedAt:         v.UpdatedAt.UTC().Format(timeLayout),
	}
}

func ToSkillRepositorySkillsResponse(preview skills.SkillRepositoryScanData) dto.SkillRepositorySkillsResponse {
	rows := make([]dto.SkillRepositoryDetectedSkill, 0, len(preview.DetectedSkills))
	for _, row := range preview.DetectedSkills {
		rows = append(rows, toSkillRepositoryDetectedSkill(row))
	}
	return dto.SkillRepositorySkillsResponse{Items: rows, Total: len(rows), CommitSHA: preview.CommitSHA, VersionID: preview.VersionID, Truncated: preview.Truncated, Limit: preview.Limit, IssueCode: preview.IssueCode}
}

func ToSkillRepositoryContentsResponse(contents skills.SkillRepositoryContents) dto.SkillRepositoryContentsResponse {
	items := make([]dto.SkillRepositoryContent, 0, len(contents.Items))
	for _, content := range contents.Items {
		items = append(items, dto.SkillRepositoryContent{Name: content.Name, Path: content.Path, Content: content.Content})
	}
	return dto.SkillRepositoryContentsResponse{Items: items, CommitSHA: contents.CommitSHA, VersionID: contents.VersionID}
}

func ToSkillImportResponse(result skills.SkillContentImportResult) dto.SkillImportResponse {
	imported := make([]dto.SkillRepositoryDetectedSkill, 0, len(result.ImportedSkills))
	for _, row := range result.ImportedSkills {
		imported = append(imported, toSkillRepositoryDetectedSkill(row))
	}
	warnings := make([]dto.SkillImportWarning, 0, len(result.Warnings))
	for _, warning := range result.Warnings {
		warnings = append(warnings, toSkillImportWarning(warning))
	}
	return dto.SkillImportResponse{
		Skill:          ToSkillWithRepositories(result.Skill, result.Repositories),
		ImportedSkills: imported,
		CommitSHA:      result.CommitSHA,
		VersionID:      result.VersionID,
		SkillCount:     result.SkillCount,
		Warnings:       warnings,
	}
}

func ToSkillRepositoryBackup(item skills.SkillRepositoryBackup) dto.SkillRepositoryBackup {
	return dto.SkillRepositoryBackup{
		TagName:   item.TagName,
		Name:      item.Name,
		CommitSHA: item.CommitSHA,
		VersionID: item.VersionID,
		CreatedAt: optionalTime(&item.CreatedAt),
	}
}

func ToSkillRepositoryBackupListResponse(page skills.SkillRepositoryBackupPage) dto.SkillRepositoryBackupListResponse {
	items := make([]dto.SkillRepositoryBackup, 0, len(page.Items))
	for _, item := range page.Items {
		items = append(items, ToSkillRepositoryBackup(item))
	}
	return dto.SkillRepositoryBackupListResponse{
		Items:   items,
		Page:    page.Page,
		PerPage: page.PerPage,
		HasMore: page.HasMore,
	}
}

func ToSkillVersion(version skills.SkillVersion) dto.SkillVersion {
	return dto.SkillVersion{
		ID: version.ID, ContentID: version.ContentID, ContentVersionID: version.ContentVersionID,
		RootDigest: version.RootDigest, FileCount: version.FileCount, SizeBytes: version.SizeBytes,
		SkillCount: version.SkillCount, CreatedBy: version.CreatedBy, CreatedAt: version.CreatedAt.UTC().Format(timeLayout),
	}
}

func ToSkillVersionListResponse(page skills.SkillVersionPage) dto.SkillVersionListResponse {
	items := make([]dto.SkillVersion, 0, len(page.Items))
	for _, version := range page.Items {
		items = append(items, ToSkillVersion(version))
	}
	return dto.SkillVersionListResponse{Items: items, Page: page.Page, PerPage: page.PerPage, HasMore: page.HasMore}
}

func toSkillRepositoryDetectedSkill(row skills.SkillRepositoryDetectedSkill) dto.SkillRepositoryDetectedSkill {
	return dto.SkillRepositoryDetectedSkill{Name: row.Name, Description: row.Description, Path: row.Path, Layout: row.Layout, SizeBytes: row.SizeBytes, Status: row.Status, IssueCode: row.IssueCode, Frontmatter: append([]string(nil), row.Frontmatter...)}
}

func toSkillImportWarning(warning skills.SkillImportWarning) dto.SkillImportWarning {
	return dto.SkillImportWarning{
		Code:       warning.Code,
		Message:    warning.Message,
		Path:       warning.Path,
		SizeBytes:  warning.SizeBytes,
		LimitBytes: warning.LimitBytes,
	}
}

func ToSkillListResponse(items []store.Skill, repositories map[string]skills.SkillRepositories, page, perPage int, total int64, hasMore bool) dto.SkillListResponse {
	out := make([]dto.Skill, 0, len(items))
	for _, item := range items {
		out = append(out, ToSkillWithRepositories(item, repositories[item.ID]))
	}
	return dto.SkillListResponse{Items: out, Page: page, PerPage: perPage, Total: total, HasMore: hasMore}
}

func ToAgentSkillBindingResponse(result skills.AgentSkillBindingResult) dto.AgentSkillBindingResponse {
	return dto.AgentSkillBindingResponse{AgentID: result.AgentID, SkillID: result.SkillID, Branch: result.Branch, Unbound: result.Unbound}
}

func ToAgentSkillBindingSummaries(bindings []skills.AgentSkillBindingSummary) []dto.AgentSkillBindingSummary {
	out := make([]dto.AgentSkillBindingSummary, 0, len(bindings))
	for _, binding := range bindings {
		out = append(out, dto.AgentSkillBindingSummary{
			ID:          binding.ID,
			WorkspaceID: binding.WorkspaceID,
			AgentID:     binding.AgentID,
			SkillID:     binding.SkillID,
			Branch:      binding.Branch,
			CreatedBy:   binding.CreatedBy,
			UpdatedBy:   binding.UpdatedBy,
			CreatedAt:   binding.CreatedAt.UTC().Format(timeLayout),
			UpdatedAt:   binding.UpdatedAt.UTC().Format(timeLayout),
		})
	}
	return out
}

func ToAgentSkillBindingsResponse(summary skills.AgentSkillBindingsSummary) dto.AgentSkillBindingsResponse {
	ownedAgents := make([]dto.AgentOwnership, 0, len(summary.OwnedAgents))
	for _, agent := range summary.OwnedAgents {
		ownedAgents = append(ownedAgents, dto.AgentOwnership{ID: agent.ID, Name: agent.Name, DisplayName: agent.DisplayName})
	}
	skills := make([]dto.AgentSkillBindingSkill, 0, len(summary.Skills))
	for _, skill := range summary.Skills {
		skills = append(skills, dto.AgentSkillBindingSkill{
			SkillID:          skill.ID,
			WorkspaceID:      skill.WorkspaceID,
			Slug:             skill.Slug,
			Name:             skill.Name,
			Description:      skill.Description,
			ContentID:        skill.ContentID,
			ContentVersionID: skill.ContentVersionID,
			IsActive:         skill.IsActive,
			Role:             skill.Role,
			CanManage:        skill.CanManage,
			CanBind:          skill.CanBind,
			Repository:       ToResourceRepositoryRef(skill.Repository),
			UpdatedAt:        skill.UpdatedAt.UTC().Format(timeLayout),
		})
	}
	return dto.AgentSkillBindingsResponse{OwnedAgents: ownedAgents, Bindings: ToAgentSkillBindingSummaries(summary.Bindings), Skills: skills}
}

func ToAgentSkillAccessBatchResponse(batch skills.AgentSkillAccessBatch) dto.AgentSkillAccessBatchResponse {
	out := dto.AgentSkillAccessBatchResponse{
		Agents:           make(map[string][]dto.AgentAccessibleSkill, len(batch.Agents)),
		SyncToken:        batch.SyncToken,
		SyncTokenExpires: optionalTime(&batch.SyncTokenExpires),
	}
	if batch.SyncTokenExpires.IsZero() {
		out.SyncTokenExpires = ""
	}
	for agentID, skills := range batch.Agents {
		converted := make([]dto.AgentAccessibleSkill, 0, len(skills))
		for _, skill := range skills {
			converted = append(converted, dto.AgentAccessibleSkill{ID: skill.ID, WorkspaceID: skill.WorkspaceID, Name: skill.Name, Description: skill.Description, ContentID: skill.ContentID, ContentVersionID: skill.ContentVersionID, Repository: ToResourceRepositoryRef(skill.Repository), Branch: skill.Branch, PermissionSetAt: skill.PermissionSetAt.UTC().Format(timeLayout), UpdatedAt: skill.UpdatedAt.UTC().Format(timeLayout)})
		}
		out.Agents[agentID] = converted
	}
	return out
}

func ToSkillPermissionGrant(grant skills.SkillPermissionGrant) dto.SkillPermissionGrant {
	return dto.SkillPermissionGrant{ID: grant.ID, WorkspaceID: grant.WorkspaceID, SkillID: grant.SkillID, SubjectType: grant.SubjectType, SubjectID: grant.SubjectID, Role: grant.Role, CreatedBy: grant.CreatedBy, UpdatedBy: grant.UpdatedBy, CreatedAt: grant.CreatedAt.UTC().Format(timeLayout), UpdatedAt: grant.UpdatedAt.UTC().Format(timeLayout)}
}

func ToSkillPermissionsResponse(summary skills.SkillPermissionsSummary) dto.SkillPermissionsResponse {
	members := make([]dto.SkillPermissionGrant, 0, len(summary.Members))
	for _, grant := range summary.Members {
		members = append(members, ToSkillPermissionGrant(grant))
	}
	var owner *dto.SkillPermissionGrant
	if summary.Owner != nil {
		converted := ToSkillPermissionGrant(*summary.Owner)
		owner = &converted
	}
	return dto.SkillPermissionsResponse{MyRole: summary.MyRole, CanManage: summary.CanManage, Owner: owner, Members: members}
}
