package repository

import (
	"context"
	"fmt"
	"strings"

	"chorus.services/bzzz/gitea"
	"chorus.services/bzzz/github"
)

// DefaultProviderFactory implements ProviderFactory
type DefaultProviderFactory struct{}

// CreateProvider creates a task provider based on configuration
func (f *DefaultProviderFactory) CreateProvider(ctx context.Context, config *Config) (TaskProvider, error) {
	switch strings.ToLower(config.Provider) {
	case "gitea":
		return f.createGiteaProvider(ctx, config)
	case "github":
		return f.createGitHubProvider(ctx, config)
	default:
		return nil, fmt.Errorf("unsupported provider: %s", config.Provider)
	}
}

// SupportedProviders returns list of supported providers
func (f *DefaultProviderFactory) SupportedProviders() []string {
	return []string{"gitea", "github"}
}

// createGiteaProvider creates a Gitea task provider
func (f *DefaultProviderFactory) createGiteaProvider(ctx context.Context, config *Config) (TaskProvider, error) {
	giteaConfig := &gitea.Config{
		BaseURL:     config.BaseURL,
		AccessToken: config.AccessToken,
		Owner:       config.Owner,
		Repository:  config.Repository,
		TaskLabel:   config.TaskLabel,
		InProgressLabel: config.InProgressLabel,
		CompletedLabel:  config.CompletedLabel,
		Assignee:    config.Assignee,
		BaseBranch:  config.BaseBranch,
		BranchPrefix: config.BranchPrefix,
	}
	
	client, err := gitea.NewClient(ctx, giteaConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to create Gitea client: %w", err)
	}
	
	return &GiteaProvider{
		client: client,
		config: config,
	}, nil
}

// createGitHubProvider creates a GitHub task provider
func (f *DefaultProviderFactory) createGitHubProvider(ctx context.Context, config *Config) (TaskProvider, error) {
	githubConfig := &github.Config{
		AccessToken: config.AccessToken,
		Owner:       config.Owner,
		Repository:  config.Repository,
		TaskLabel:   config.TaskLabel,
		InProgressLabel: config.InProgressLabel,
		CompletedLabel:  config.CompletedLabel,
		Assignee:    config.Assignee,
		BaseBranch:  config.BaseBranch,
		BranchPrefix: config.BranchPrefix,
	}
	
	client, err := github.NewClient(ctx, githubConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to create GitHub client: %w", err)
	}
	
	return &GitHubProvider{
		client: client,
		config: config,
	}, nil
}

// GiteaProvider adapts Gitea client to TaskProvider interface
type GiteaProvider struct {
	client *gitea.Client
	config *Config
}

// ListAvailableTasks implements TaskProvider interface
func (p *GiteaProvider) ListAvailableTasks() ([]*Task, error) {
	giteaTasks, err := p.client.ListAvailableTasks()
	if err != nil {
		return nil, err
	}
	
	tasks := make([]*Task, len(giteaTasks))
	for i, gTask := range giteaTasks {
		tasks[i] = p.convertGiteaTask(gTask)
	}
	
	return tasks, nil
}

// ClaimTask implements TaskProvider interface
func (p *GiteaProvider) ClaimTask(issueNumber int64, agentID string) (*Task, error) {
	gTask, err := p.client.ClaimTask(issueNumber, agentID)
	if err != nil {
		return nil, err
	}
	
	return p.convertGiteaTask(gTask), nil
}

// CompleteTask implements TaskProvider interface
func (p *GiteaProvider) CompleteTask(issueNumber int64, agentID string, results map[string]interface{}) error {
	return p.client.CompleteTask(issueNumber, agentID, results)
}

// GetTask implements TaskProvider interface
func (p *GiteaProvider) GetTask(issueNumber int64) (*Task, error) {
	// This would need to be implemented in the Gitea client
	return nil, fmt.Errorf("GetTask not yet implemented for Gitea provider")
}

// GetConfig implements TaskProvider interface
func (p *GiteaProvider) GetConfig() *Config {
	return p.config
}

// convertGiteaTask converts a Gitea task to the unified Task format
func (p *GiteaProvider) convertGiteaTask(gTask *gitea.Task) *Task {
	labels := make([]string, len(gTask.Labels))
	for i, label := range gTask.Labels {
		labels[i] = label.Name
	}
	
	assignee := ""
	if gTask.Assignee != nil {
		assignee = gTask.Assignee.Login
	}
	
	return &Task{
		ID:                gTask.ID,
		Number:            gTask.Number,
		Title:             gTask.Title,
		Description:       gTask.Description,
		State:             gTask.State,
		Provider:          "gitea",
		Repository:        fmt.Sprintf("%s/%s", p.config.Owner, p.config.Repository),
		CreatedAt:         gTask.CreatedAt,
		UpdatedAt:         gTask.UpdatedAt,
		Assignee:          assignee,
		Labels:            labels,
		TaskType:          gTask.TaskType,
		Priority:          gTask.Priority,
		Requirements:      gTask.Requirements,
		Deliverables:      gTask.Deliverables,
		Context:           gTask.Context,
		RequiredRole:      gTask.RequiredRole,
		RequiredExpertise: gTask.RequiredExpertise,
	}
}

// GitHubProvider adapts GitHub client to TaskProvider interface
type GitHubProvider struct {
	client *github.Client
	config *Config
}

// ListAvailableTasks implements TaskProvider interface
func (p *GitHubProvider) ListAvailableTasks() ([]*Task, error) {
	githubTasks, err := p.client.ListAvailableTasks()
	if err != nil {
		return nil, err
	}
	
	tasks := make([]*Task, len(githubTasks))
	for i, gTask := range githubTasks {
		tasks[i] = p.convertGitHubTask(gTask)
	}
	
	return tasks, nil
}

// ClaimTask implements TaskProvider interface
func (p *GitHubProvider) ClaimTask(issueNumber int64, agentID string) (*Task, error) {
	gTask, err := p.client.ClaimTask(int(issueNumber), agentID)
	if err != nil {
		return nil, err
	}
	
	return p.convertGitHubTask(gTask), nil
}

// CompleteTask implements TaskProvider interface
func (p *GitHubProvider) CompleteTask(issueNumber int64, agentID string, results map[string]interface{}) error {
	return p.client.CompleteTask(int(issueNumber), agentID, results)
}

// GetTask implements TaskProvider interface
func (p *GitHubProvider) GetTask(issueNumber int64) (*Task, error) {
	// This would need to be implemented in the GitHub client
	return nil, fmt.Errorf("GetTask not yet implemented for GitHub provider")
}

// GetConfig implements TaskProvider interface
func (p *GitHubProvider) GetConfig() *Config {
	return p.config
}

// convertGitHubTask converts a GitHub task to the unified Task format
func (p *GitHubProvider) convertGitHubTask(gTask *github.Task) *Task {
	return &Task{
		ID:                gTask.ID,
		Number:            int64(gTask.Number),
		Title:             gTask.Title,
		Description:       gTask.Description,
		State:             gTask.State,
		Provider:          "github",
		Repository:        fmt.Sprintf("%s/%s", p.config.Owner, p.config.Repository),
		CreatedAt:         gTask.CreatedAt,
		UpdatedAt:         gTask.UpdatedAt,
		Assignee:          gTask.Assignee,
		Labels:            gTask.Labels,
		TaskType:          gTask.TaskType,
		Priority:          gTask.Priority,
		Requirements:      gTask.Requirements,
		Deliverables:      gTask.Deliverables,
		Context:           gTask.Context,
		RequiredRole:      "", // Would need to be parsed from GitHub task
		RequiredExpertise: []string{}, // Would need to be parsed from GitHub task
	}
}