package main

import (
	"encoding/json"
	"fmt"
	"os"
)

// OperClass defines an operator class with specific permissions
type OperClass struct {
	Name        string   `json:"name"`
	Rank        int      `json:"rank"` // Higher number = higher rank
	Description string   `json:"description"`
	Permissions []string `json:"permissions"`
	Inherits    string   `json:"inherits"` // Inherit permissions from another class
	Color       string   `json:"color"`    // Color for display purposes
	Symbol      string   `json:"symbol"`   // Symbol to display (*, @, &, etc.)
}

// Oper defines an individual operator
type Oper struct {
	Name       string   `json:"name"`
	Password   string   `json:"password"`
	Host       string   `json:"host"`
	Class      string   `json:"class"`
	Flags      []string `json:"flags"`       // Additional per-user flags
	MaxClients int      `json:"max_clients"` // Max clients this oper can handle
	Expires    string   `json:"expires"`     // Expiration date (optional)
	Contact    string   `json:"contact"`     // Contact information
	LastSeen   string   `json:"last_seen"`   // Last time this oper was online
}

// RankNames defines custom names for rank levels
type RankNames struct {
	Rank1 string `json:"rank_1"` // Default: Helper
	Rank2 string `json:"rank_2"` // Default: Moderator
	Rank3 string `json:"rank_3"` // Default: Operator
	Rank4 string `json:"rank_4"` // Default: Administrator
	Rank5 string `json:"rank_5"` // Default: Owner
	// Support for custom ranks beyond 5
	CustomRanks map[string]int `json:"custom_ranks"` // "CustomName": 6
}

// OperConfig holds the complete operator configuration
type OperConfig struct {
	Classes   []OperClass `json:"classes"`
	Opers     []Oper      `json:"opers"`
	RankNames RankNames   `json:"rank_names"`
	Settings  struct {
		RequireSSL         bool     `json:"require_ssl"`
		MaxFailedAttempts  int      `json:"max_failed_attempts"`
		LockoutDuration    int      `json:"lockout_duration_minutes"`
		AllowedCommands    []string `json:"allowed_commands"`
		LogOperActions     bool     `json:"log_oper_actions"`
		NotifyOnOperUp     bool     `json:"notify_on_oper_up"`
		AutoExpireInactive int      `json:"auto_expire_inactive_days"`
		RequireTwoFactor   bool     `json:"require_two_factor"`
	} `json:"settings"`
}

// LoadOperConfig loads operator configuration from file
func LoadOperConfig(filename string) (*OperConfig, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("failed to read oper config file: %v", err)
	}

	var config OperConfig
	if err := json.Unmarshal(data, &config); err != nil {
		return nil, fmt.Errorf("failed to parse oper config file: %v", err)
	}

	return &config, nil
}

// SaveOperConfig saves operator configuration to file
func SaveOperConfig(config *OperConfig, filename string) error {
	data, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal oper config: %v", err)
	}

	if err := os.WriteFile(filename, data, 0644); err != nil {
		return fmt.Errorf("failed to write oper config file: %v", err)
	}

	return nil
}

// GetOperClass returns the operator class by name
func (oc *OperConfig) GetOperClass(className string) *OperClass {
	for i := range oc.Classes {
		if oc.Classes[i].Name == className {
			return &oc.Classes[i]
		}
	}
	return nil
}

// GetOper returns the operator by name
func (oc *OperConfig) GetOper(operName string) *Oper {
	for i := range oc.Opers {
		if oc.Opers[i].Name == operName {
			return &oc.Opers[i]
		}
	}
	return nil
}

// GetOperPermissions returns all permissions for an operator (including inherited)
func (oc *OperConfig) GetOperPermissions(operName string) []string {
	oper := oc.GetOper(operName)
	if oper == nil {
		return nil
	}

	class := oc.GetOperClass(oper.Class)
	if class == nil {
		return oper.Flags
	}

	permissions := make(map[string]bool)

	// Add class permissions
	for _, perm := range class.Permissions {
		permissions[perm] = true
	}

	// Add inherited permissions
	if class.Inherits != "" {
		inherited := oc.GetOperClass(class.Inherits)
		if inherited != nil {
			for _, perm := range inherited.Permissions {
				permissions[perm] = true
			}
		}
	}

	// Add individual flags
	for _, flag := range oper.Flags {
		permissions[flag] = true
	}

	// Convert back to slice
	result := make([]string, 0, len(permissions))
	for perm := range permissions {
		result = append(result, perm)
	}

	return result
}

// GetRankName returns the custom name for a rank level
func (oc *OperConfig) GetRankName(rank int) string {
	switch rank {
	case 1:
		if oc.RankNames.Rank1 != "" {
			return oc.RankNames.Rank1
		}
		return "Helper"
	case 2:
		if oc.RankNames.Rank2 != "" {
			return oc.RankNames.Rank2
		}
		return "Moderator"
	case 3:
		if oc.RankNames.Rank3 != "" {
			return oc.RankNames.Rank3
		}
		return "Operator"
	case 4:
		if oc.RankNames.Rank4 != "" {
			return oc.RankNames.Rank4
		}
		return "Administrator"
	case 5:
		if oc.RankNames.Rank5 != "" {
			return oc.RankNames.Rank5
		}
		return "Owner"
	default:
		// Check custom ranks
		for name, rankNum := range oc.RankNames.CustomRanks {
			if rankNum == rank {
				return name
			}
		}
		return fmt.Sprintf("Rank %d", rank)
	}
}

// GetOperRankName returns the rank name for an operator
func (oc *OperConfig) GetOperRankName(operName string) string {
	oper := oc.GetOper(operName)
	if oper == nil {
		return "Unknown"
	}

	class := oc.GetOperClass(oper.Class)
	if class == nil {
		return "Unknown"
	}

	return oc.GetRankName(class.Rank)
}

// SetCustomRankName allows adding custom rank names at runtime
func (oc *OperConfig) SetCustomRankName(name string, rank int) {
	if oc.RankNames.CustomRanks == nil {
		oc.RankNames.CustomRanks = make(map[string]int)
	}
	oc.RankNames.CustomRanks[name] = rank
}

// HasPermission checks if an operator has a specific permission
func (oc *OperConfig) HasPermission(operName, permission string) bool {
	permissions := oc.GetOperPermissions(operName)
	for _, perm := range permissions {
		if perm == permission || perm == "*" { // * grants all permissions
			return true
		}
	}
	return false
}

// GetOperRank returns the rank of an operator
func (oc *OperConfig) GetOperRank(operName string) int {
	oper := oc.GetOper(operName)
	if oper == nil {
		return 0
	}

	class := oc.GetOperClass(oper.Class)
	if class == nil {
		return 0
	}

	return class.Rank
}

// CanOperateOn checks if oper1 can perform actions on oper2 (based on rank)
func (oc *OperConfig) CanOperateOn(oper1Name, oper2Name string) bool {
	rank1 := oc.GetOperRank(oper1Name)
	rank2 := oc.GetOperRank(oper2Name)

	// Higher rank can operate on lower rank
	// Same rank cannot operate on each other (unless they have override permission)
	return rank1 > rank2 || oc.HasPermission(oper1Name, "override_rank")
}

// DefaultOperConfig returns a default operator configuration
func DefaultOperConfig() *OperConfig {
	return &OperConfig{
		Classes: []OperClass{
			{
				Name:        "helper",
				Rank:        1,
				Description: "Helper - Basic moderation commands",
				Permissions: []string{"kick", "topic", "mode_channel"},
				Color:       "green",
				Symbol:      "%",
			},
			{
				Name:        "moderator",
				Rank:        2,
				Description: "Moderator - Channel and user management",
				Permissions: []string{"ban", "unban", "kick", "mute", "topic", "mode_channel", "mode_user", "who_override"},
				Inherits:    "helper",
				Color:       "blue",
				Symbol:      "@",
			},
			{
				Name:        "operator",
				Rank:        3,
				Description: "Operator - Server management commands",
				Permissions: []string{"kill", "gline", "rehash", "connect", "squit", "wallops", "operwall"},
				Inherits:    "moderator",
				Color:       "red",
				Symbol:      "*",
			},
			{
				Name:        "admin",
				Rank:        4,
				Description: "Administrator - Full server control",
				Permissions: []string{"*"}, // All permissions
				Color:       "purple",
				Symbol:      "&",
			},
			{
				Name:        "owner",
				Rank:        5,
				Description: "Server Owner - Ultimate authority",
				Permissions: []string{"*", "override_rank", "shutdown", "restart"},
				Color:       "gold",
				Symbol:      "~",
			},
		},
		Opers: []Oper{
			{
				Name:       "admin",
				Password:   "changeme",
				Host:       "*@localhost",
				Class:      "admin",
				MaxClients: 1000,
				Contact:    "admin@example.com",
			},
		},
		RankNames: RankNames{
			Rank1:       "Helper",        // Customizable: "Support Staff", "Junior Mod", etc.
			Rank2:       "Moderator",     // Customizable: "Channel Mod", "Guard", etc.
			Rank3:       "Operator",      // Customizable: "IRC Operator", "Senior Staff", etc.
			Rank4:       "Administrator", // Customizable: "Admin", "Server Admin", etc.
			Rank5:       "Owner",         // Customizable: "Root", "Founder", etc.
			CustomRanks: map[string]int{
				// Example: "Super Admin": 6,
				// Example: "Network Founder": 10,
			},
		},
		Settings: struct {
			RequireSSL         bool     `json:"require_ssl"`
			MaxFailedAttempts  int      `json:"max_failed_attempts"`
			LockoutDuration    int      `json:"lockout_duration_minutes"`
			AllowedCommands    []string `json:"allowed_commands"`
			LogOperActions     bool     `json:"log_oper_actions"`
			NotifyOnOperUp     bool     `json:"notify_on_oper_up"`
			AutoExpireInactive int      `json:"auto_expire_inactive_days"`
			RequireTwoFactor   bool     `json:"require_two_factor"`
		}{
			RequireSSL:         false,
			MaxFailedAttempts:  3,
			LockoutDuration:    30,
			AllowedCommands:    []string{"OPER", "KILL", "GLINE", "REHASH", "WALLOPS"},
			LogOperActions:     true,
			NotifyOnOperUp:     true,
			AutoExpireInactive: 365,
			RequireTwoFactor:   false,
		},
	}
}
