package store

import (
	"context"
	"fmt"
	"time"

	"github.com/yaoapp/gou/model"
	"github.com/yaoapp/kun/maps"
	"github.com/yaoapp/yao/agent/robot/types"
	"github.com/yaoapp/yao/agent/robot/utils"
)

// RobotRecord - persistent storage for robot member
// Maps to __yao.member model
type RobotRecord struct {
	ID             int64  `json:"id,omitempty"`    // Auto-increment primary key
	MemberID       string `json:"member_id"`       // Unique robot identifier
	TeamID         string `json:"team_id"`         // Team ID
	MemberType     string `json:"member_type"`     // Always "robot" for robots
	Status         string `json:"status"`          // Member status: active | inactive | pending | suspended
	RobotStatus    string `json:"robot_status"`    // Robot status: idle | working | paused | error | maintenance
	AutonomousMode bool   `json:"autonomous_mode"` // Whether autonomous mode is enabled

	// Profile
	DisplayName string `json:"display_name"`  // Display name
	Bio         string `json:"bio,omitempty"` // Robot description
	Avatar      string `json:"avatar,omitempty"`

	// Identity & Role
	SystemPrompt string `json:"system_prompt"` // System prompt
	RoleID       string `json:"role_id"`       // Role within team
	ManagerID    string `json:"manager_id"`    // Direct manager user_id (who manages this robot)

	// Communication
	RobotEmail        string      `json:"robot_email"`                  // Deprecated: Robot email address
	AuthorizedSenders interface{} `json:"authorized_senders,omitempty"` // Email whitelist (JSON array)
	EmailFilterRules  interface{} `json:"email_filter_rules,omitempty"` // Email filter rules (JSON array)

	// Capabilities
	RobotConfig   interface{} `json:"robot_config"`             // Robot config JSON
	Agents        interface{} `json:"agents,omitempty"`         // Accessible agents (JSON array)
	MCPServers    interface{} `json:"mcp_servers,omitempty"`    // MCP servers (JSON array)
	LanguageModel string      `json:"language_model,omitempty"` // Language model name
	Workspace     string      `json:"workspace,omitempty"`      // Workspace ID bound to this robot

	// Limits
	CostLimit float64 `json:"cost_limit,omitempty"` // Monthly cost limit USD

	// Ownership & Audit
	InvitedBy string     `json:"invited_by,omitempty"` // Who created/added this robot
	JoinedAt  *time.Time `json:"joined_at,omitempty"`  // When robot was created

	// Timestamps
	CreatedAt *time.Time `json:"created_at,omitempty"`
	UpdatedAt *time.Time `json:"updated_at,omitempty"`

	// Yao Permission Fields (automatically handled by Yao model when permission:true)
	// These fields are passed through to the model layer for permission control
	YaoCreatedBy string `json:"__yao_created_by,omitempty"` // Creator user_id (set on create)
	YaoUpdatedBy string `json:"__yao_updated_by,omitempty"` // Updater user_id (set on update)
	YaoTeamID    string `json:"__yao_team_id,omitempty"`    // Permission team scope
	YaoTenantID  string `json:"__yao_tenant_id,omitempty"`  // Permission tenant scope
}

// RobotListOptions - options for listing robot records
type RobotListOptions struct {
	TeamID   string            `json:"team_id,omitempty"`
	Status   types.RobotStatus `json:"status,omitempty"`
	Keywords string            `json:"keywords,omitempty"` // Search in display_name
	Limit    int               `json:"limit,omitempty"`
	Offset   int               `json:"offset,omitempty"`
	Page     int               `json:"page,omitempty"`
	PageSize int               `json:"pagesize,omitempty"`
	OrderBy  string            `json:"order_by,omitempty"`
}

// RobotStore - persistent storage for robot members
type RobotStore struct {
	modelID string
}

// NewRobotStore creates a new robot store instance
func NewRobotStore() *RobotStore {
	return &RobotStore{
		modelID: "__yao.member",
	}
}

// robotFields are the fields to select when loading robots
var robotFields = []interface{}{
	// Basic
	"id",
	"member_id",
	"team_id",
	"member_type",
	"status",
	"robot_status",
	"autonomous_mode",

	// Profile
	"display_name",
	"bio",
	"avatar",

	// Identity & Role
	"system_prompt",
	"role_id",
	"manager_id",

	// Communication
	"robot_email",
	"authorized_senders",
	"email_filter_rules",

	// Capabilities
	"robot_config",
	"agents",
	"mcp_servers",
	"language_model",
	"workspace",

	// Limits
	"cost_limit",

	// Ownership & Audit
	"invited_by",
	"joined_at",

	// Timestamps
	"created_at",
	"updated_at",

	// Yao Permission Fields (for access control)
	"__yao_created_by",
	"__yao_updated_by",
	"__yao_team_id",
	"__yao_tenant_id",
}

// Save creates or updates a robot member record
func (s *RobotStore) Save(ctx context.Context, record *RobotRecord) error {
	mod := model.Select(s.modelID)
	if mod == nil {
		return fmt.Errorf("model %s not found", s.modelID)
	}

	// Ensure member_type is robot
	record.MemberType = "robot"

	data := s.recordToMap(record)

	// Check if record exists by member_id
	existing, err := s.Get(ctx, record.MemberID)
	if err == nil && existing != nil {
		// Update existing record
		_, err = mod.UpdateWhere(
			model.QueryParam{
				Wheres: []model.QueryWhere{
					{Column: "member_id", Value: record.MemberID},
				},
			},
			data,
		)
		if err != nil {
			return fmt.Errorf("failed to update robot record: %w", err)
		}
		return nil
	}

	// Create new record
	_, err = mod.Create(data)
	if err != nil {
		return fmt.Errorf("failed to create robot record: %w", err)
	}
	return nil
}

// Get retrieves a robot record by member_id
func (s *RobotStore) Get(ctx context.Context, memberID string) (*RobotRecord, error) {
	mod := model.Select(s.modelID)
	if mod == nil {
		return nil, fmt.Errorf("model %s not found", s.modelID)
	}

	rows, err := mod.Get(model.QueryParam{
		Select: robotFields,
		Wheres: []model.QueryWhere{
			{Column: "member_id", Value: memberID},
			{Column: "member_type", Value: "robot"},
		},
		Limit: 1,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to get robot record: %w", err)
	}

	if len(rows) == 0 {
		return nil, nil
	}

	return s.mapToRecord(rows[0])
}

// List retrieves robot records with filters
func (s *RobotStore) List(ctx context.Context, opts *RobotListOptions) ([]*RobotRecord, int, error) {
	mod := model.Select(s.modelID)
	if mod == nil {
		return nil, 0, fmt.Errorf("model %s not found", s.modelID)
	}

	// Build where conditions - only require member_type=robot
	wheres := []model.QueryWhere{
		{Column: "member_type", Value: "robot"},
	}

	if opts != nil {
		if opts.TeamID != "" {
			wheres = append(wheres, model.QueryWhere{Column: "team_id", Value: opts.TeamID})
		}
		if opts.Status != "" {
			wheres = append(wheres, model.QueryWhere{Column: "robot_status", Value: string(opts.Status)})
		}
		if opts.Keywords != "" {
			wheres = append(wheres, model.QueryWhere{
				Column: "display_name",
				OP:     "like",
				Value:  "%" + opts.Keywords + "%",
			})
		}
	}

	// Build order
	orders := []model.QueryOrder{}
	if opts != nil && opts.OrderBy != "" {
		orders = append(orders, model.QueryOrder{Column: opts.OrderBy})
	} else {
		orders = append(orders, model.QueryOrder{Column: "created_at", Option: "desc"})
	}

	// Determine pagination
	page := 1
	pageSize := 100
	if opts != nil {
		if opts.Page > 0 {
			page = opts.Page
		}
		if opts.PageSize > 0 {
			pageSize = opts.PageSize
		}
		// Limit overrides PageSize for simple limit queries
		if opts.Limit > 0 {
			pageSize = opts.Limit
		}
	}

	// Execute paginated query
	result, err := mod.Paginate(model.QueryParam{
		Select: robotFields,
		Wheres: wheres,
		Orders: orders,
	}, page, pageSize)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list robots: %w", err)
	}

	// Get total count
	total := 0
	if t, ok := result.Get("total").(int); ok {
		total = t
	}

	// Parse records
	records := []*RobotRecord{}
	data := result.Get("data")
	switch rows := data.(type) {
	case []maps.MapStr:
		for _, row := range rows {
			record, err := s.mapToRecord(map[string]interface{}(row))
			if err != nil {
				continue // skip invalid records
			}
			records = append(records, record)
		}
	case []map[string]interface{}:
		for _, row := range rows {
			record, err := s.mapToRecord(row)
			if err != nil {
				continue // skip invalid records
			}
			records = append(records, record)
		}
	}

	return records, total, nil
}

// Delete removes a robot member by member_id
func (s *RobotStore) Delete(ctx context.Context, memberID string) error {
	mod := model.Select(s.modelID)
	if mod == nil {
		return fmt.Errorf("model %s not found", s.modelID)
	}

	_, err := mod.DeleteWhere(model.QueryParam{
		Wheres: []model.QueryWhere{
			{Column: "member_id", Value: memberID},
			{Column: "member_type", Value: "robot"},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to delete robot record: %w", err)
	}

	return nil
}

// UpdateConfig updates only the robot_config field
func (s *RobotStore) UpdateConfig(ctx context.Context, memberID string, config interface{}) error {
	mod := model.Select(s.modelID)
	if mod == nil {
		return fmt.Errorf("model %s not found", s.modelID)
	}

	data := map[string]interface{}{
		"robot_config": config,
	}

	_, err := mod.UpdateWhere(
		model.QueryParam{
			Wheres: []model.QueryWhere{
				{Column: "member_id", Value: memberID},
				{Column: "member_type", Value: "robot"},
			},
		},
		data,
	)
	if err != nil {
		return fmt.Errorf("failed to update robot config: %w", err)
	}

	return nil
}

// UpdateStatus updates the robot_status field
func (s *RobotStore) UpdateStatus(ctx context.Context, memberID string, status types.RobotStatus) error {
	mod := model.Select(s.modelID)
	if mod == nil {
		return fmt.Errorf("model %s not found", s.modelID)
	}

	data := map[string]interface{}{
		"robot_status": string(status),
	}

	_, err := mod.UpdateWhere(
		model.QueryParam{
			Wheres: []model.QueryWhere{
				{Column: "member_id", Value: memberID},
				{Column: "member_type", Value: "robot"},
			},
		},
		data,
	)
	if err != nil {
		return fmt.Errorf("failed to update robot status: %w", err)
	}

	return nil
}

// recordToMap converts RobotRecord to map for model operations
func (s *RobotStore) recordToMap(record *RobotRecord) map[string]interface{} {
	data := map[string]interface{}{
		// Required fields
		"member_id":       record.MemberID,
		"team_id":         record.TeamID,
		"member_type":     "robot",
		"autonomous_mode": record.AutonomousMode,
	}

	// Status
	if record.Status != "" {
		data["status"] = record.Status
	} else {
		data["status"] = "active"
	}
	if record.RobotStatus != "" {
		data["robot_status"] = record.RobotStatus
	} else {
		data["robot_status"] = "idle"
	}

	// Profile
	if record.DisplayName != "" {
		data["display_name"] = record.DisplayName
	}
	if record.Bio != "" {
		data["bio"] = record.Bio
	}
	if record.Avatar != "" {
		data["avatar"] = record.Avatar
	}

	// Identity & Role
	if record.SystemPrompt != "" {
		data["system_prompt"] = record.SystemPrompt
	}
	if record.RoleID != "" {
		data["role_id"] = record.RoleID
	}
	if record.ManagerID != "" {
		data["manager_id"] = record.ManagerID
	}

	// Communication
	if record.RobotEmail != "" {
		data["robot_email"] = record.RobotEmail
	}
	if record.AuthorizedSenders != nil {
		data["authorized_senders"] = record.AuthorizedSenders
	}
	if record.EmailFilterRules != nil {
		data["email_filter_rules"] = record.EmailFilterRules
	}

	// Capabilities
	if record.RobotConfig != nil {
		data["robot_config"] = record.RobotConfig
	}
	if record.Agents != nil {
		data["agents"] = record.Agents
	}
	if record.MCPServers != nil {
		data["mcp_servers"] = record.MCPServers
	}
	if record.LanguageModel != "" {
		data["language_model"] = record.LanguageModel
	}
	if record.Workspace != "" {
		data["workspace"] = record.Workspace
	}

	// Limits
	if record.CostLimit > 0 {
		data["cost_limit"] = record.CostLimit
	}

	// Ownership & Audit
	if record.InvitedBy != "" {
		data["invited_by"] = record.InvitedBy
	}
	if record.JoinedAt != nil {
		// Format time for Gou model (expects string format)
		data["joined_at"] = record.JoinedAt.Format("2006-01-02 15:04:05")
	}

	// Yao Permission Fields - pass through for model layer
	if record.YaoCreatedBy != "" {
		data["__yao_created_by"] = record.YaoCreatedBy
	}
	if record.YaoUpdatedBy != "" {
		data["__yao_updated_by"] = record.YaoUpdatedBy
	}
	if record.YaoTeamID != "" {
		data["__yao_team_id"] = record.YaoTeamID
	}
	if record.YaoTenantID != "" {
		data["__yao_tenant_id"] = record.YaoTenantID
	}

	return data
}

// mapToRecord converts a model row to RobotRecord
func (s *RobotStore) mapToRecord(row map[string]interface{}) (*RobotRecord, error) {
	record := &RobotRecord{}

	// Basic fields
	if v, ok := row["id"]; ok {
		switch id := v.(type) {
		case float64:
			record.ID = int64(id)
		case int64:
			record.ID = id
		case int:
			record.ID = int64(id)
		}
	}
	if v, ok := row["member_id"].(string); ok {
		record.MemberID = v
	}
	if v, ok := row["team_id"].(string); ok {
		record.TeamID = v
	}
	if v, ok := row["member_type"].(string); ok {
		record.MemberType = v
	}
	if v, ok := row["status"].(string); ok {
		record.Status = v
	}
	if v, ok := row["robot_status"].(string); ok {
		record.RobotStatus = v
	}
	if v, ok := row["autonomous_mode"]; ok {
		record.AutonomousMode = utils.ToBool(v)
	}

	// Profile
	if v, ok := row["display_name"].(string); ok {
		record.DisplayName = v
	}
	if v, ok := row["bio"].(string); ok {
		record.Bio = v
	}
	if v, ok := row["avatar"].(string); ok {
		record.Avatar = v
	}

	// Identity & Role
	if v, ok := row["system_prompt"].(string); ok {
		record.SystemPrompt = v
	}
	if v, ok := row["role_id"].(string); ok {
		record.RoleID = v
	}
	if v, ok := row["manager_id"].(string); ok {
		record.ManagerID = v
	}

	// Communication
	if v, ok := row["robot_email"].(string); ok {
		record.RobotEmail = v
	}
	if v := row["authorized_senders"]; v != nil {
		record.AuthorizedSenders = utils.ToJSONValue(v)
	}
	if v := row["email_filter_rules"]; v != nil {
		record.EmailFilterRules = utils.ToJSONValue(v)
	}

	// Capabilities
	if v := row["robot_config"]; v != nil {
		record.RobotConfig = utils.ToJSONValue(v)
	}
	if v := row["agents"]; v != nil {
		record.Agents = utils.ToJSONValue(v)
	}
	if v := row["mcp_servers"]; v != nil {
		record.MCPServers = utils.ToJSONValue(v)
	}
	if v, ok := row["language_model"].(string); ok {
		record.LanguageModel = v
	}
	if v, ok := row["workspace"].(string); ok {
		record.Workspace = v
	}

	// Limits
	if v := row["cost_limit"]; v != nil {
		record.CostLimit = utils.ToFloat64(v)
	}

	// Ownership & Audit
	if v, ok := row["invited_by"].(string); ok {
		record.InvitedBy = v
	}
	if v := row["joined_at"]; v != nil {
		record.JoinedAt = utils.ToTimestamp(v)
	}

	// Timestamps
	if v := row["created_at"]; v != nil {
		record.CreatedAt = utils.ToTimestamp(v)
	}
	if v := row["updated_at"]; v != nil {
		record.UpdatedAt = utils.ToTimestamp(v)
	}

	// Yao Permission Fields
	if v, ok := row["__yao_created_by"].(string); ok {
		record.YaoCreatedBy = v
	}
	if v, ok := row["__yao_updated_by"].(string); ok {
		record.YaoUpdatedBy = v
	}
	if v, ok := row["__yao_team_id"].(string); ok {
		record.YaoTeamID = v
	}
	if v, ok := row["__yao_tenant_id"].(string); ok {
		record.YaoTenantID = v
	}

	return record, nil
}

// ToRobot converts a RobotRecord to types.Robot
func (r *RobotRecord) ToRobot() (*types.Robot, error) {
	robot := &types.Robot{
		MemberID:       r.MemberID,
		TeamID:         r.TeamID,
		DisplayName:    r.DisplayName,
		Bio:            r.Bio,
		SystemPrompt:   r.SystemPrompt,
		AutonomousMode: r.AutonomousMode,
		RobotEmail:     r.RobotEmail,
		LanguageModel:  r.LanguageModel,
		Workspace:      r.Workspace,
	}

	// Parse robot_status
	if r.RobotStatus != "" {
		robot.Status = types.RobotStatus(r.RobotStatus)
	} else {
		robot.Status = types.RobotIdle
	}

	// Parse robot_config
	if r.RobotConfig != nil {
		config, err := types.ParseConfig(r.RobotConfig)
		if err != nil {
			return nil, fmt.Errorf("failed to parse robot_config: %w", err)
		}
		robot.Config = config
	}

	// Ensure Config exists for merging agents/mcp_servers
	if robot.Config == nil {
		robot.Config = &types.Config{}
	}
	if robot.Config.Resources == nil {
		robot.Config.Resources = &types.Resources{}
	}

	// Merge agents from member table into Config.Resources.Agents
	if r.Agents != nil {
		agents := parseStringSlice(r.Agents)
		if len(agents) > 0 {
			robot.Config.Resources.Agents = agents
		}
	}

	// Merge mcp_servers from member table into Config.Resources.MCP
	if r.MCPServers != nil {
		mcpServers := parseStringSlice(r.MCPServers)
		if len(mcpServers) > 0 {
			// Convert string slice to MCPConfig slice (each server ID becomes an MCPConfig)
			for _, serverID := range mcpServers {
				robot.Config.Resources.MCP = append(robot.Config.Resources.MCP, types.MCPConfig{
					ID: serverID,
					// Tools empty means all tools available
				})
			}
		}
	}

	return robot, nil
}

// parseStringSlice converts interface{} to []string
func parseStringSlice(v interface{}) []string {
	if v == nil {
		return nil
	}
	switch val := v.(type) {
	case []string:
		return val
	case []interface{}:
		result := make([]string, 0, len(val))
		for _, item := range val {
			if s, ok := item.(string); ok {
				result = append(result, s)
			}
		}
		return result
	}
	return nil
}

// FromRobot creates a RobotRecord from types.Robot
func FromRobot(robot *types.Robot) *RobotRecord {
	record := &RobotRecord{
		MemberID:       robot.MemberID,
		TeamID:         robot.TeamID,
		DisplayName:    robot.DisplayName,
		Bio:            robot.Bio,
		SystemPrompt:   robot.SystemPrompt,
		RobotStatus:    string(robot.Status),
		AutonomousMode: robot.AutonomousMode,
		RobotEmail:     robot.RobotEmail,
		LanguageModel:  robot.LanguageModel,
		Workspace:      robot.Workspace,
		MemberType:     "robot",
		Status:         "active",
	}

	if robot.Config != nil {
		record.RobotConfig = robot.Config
	}

	return record
}
