import Foundation
import Observation
import SwiftUI

/// Manages categories for rituals, including global presets and user-created categories.
@MainActor
@Observable
final class CategoryStore {
    
    private let userDefaultsKey = "userCategories"
    private let presetColorsKey = "presetCategoryColors"
    
    /// All categories (presets + user-created), sorted alphabetically with presets first
    private(set) var categories: [Category] = []
    
    init() {
        loadCategories()
    }
    
    // MARK: - Public API
    
    /// Get a category by name
    func category(named name: String) -> Category? {
        categories.first { $0.name == name }
    }
    
    /// Get color for a category name, with fallback
    func color(for categoryName: String) -> Color {
        category(named: categoryName)?.color ?? .gray
    }
    
    /// Add a new user category
    func addCategory(name: String, colorName: String) {
        let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmedName.isEmpty else { return }
        
        // Don't add if name already exists
        guard category(named: trimmedName) == nil else { return }
        
        let newCategory = Category.create(name: trimmedName, colorName: colorName)
        categories.append(newCategory)
        sortCategories()
        saveUserCategories()
    }
    
    /// Update a category's properties
    func updateCategory(_ category: Category, name: String? = nil, colorName: String? = nil) {
        guard let index = categories.firstIndex(where: { $0.id == category.id }) else { return }
        
        if category.isPreset {
            // Presets can only change color
            if let colorName {
                categories[index].colorName = colorName
                savePresetColors()
            }
        } else {
            // User categories can change name and color
            if let name {
                let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
                // Ensure no duplicate names
                if !trimmedName.isEmpty && self.category(named: trimmedName) == nil {
                    categories[index].name = trimmedName
                }
            }
            if let colorName {
                categories[index].colorName = colorName
            }
            sortCategories()
            saveUserCategories()
        }
    }
    
    /// Delete a user category (presets cannot be deleted)
    func deleteCategory(_ category: Category) {
        guard !category.isPreset else { return }
        categories.removeAll { $0.id == category.id }
        saveUserCategories()
    }
    
    /// Check if a category name is available
    func isNameAvailable(_ name: String, excluding: Category? = nil) -> Bool {
        let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
        return categories.first { 
            $0.name.lowercased() == trimmedName.lowercased() && $0.id != excluding?.id 
        } == nil
    }
    
    // MARK: - Persistence
    
    private func loadCategories() {
        // Start with default presets
        var loadedCategories = Category.defaultPresets
        
        // Apply saved preset colors
        if let presetColors = UserDefaults.standard.dictionary(forKey: presetColorsKey) as? [String: String] {
            for i in loadedCategories.indices where loadedCategories[i].isPreset {
                if let savedColor = presetColors[loadedCategories[i].name] {
                    loadedCategories[i].colorName = savedColor
                }
            }
        }
        
        // Load user categories
        if let data = UserDefaults.standard.data(forKey: userDefaultsKey),
           let userCategories = try? JSONDecoder().decode([Category].self, from: data) {
            loadedCategories.append(contentsOf: userCategories)
        }
        
        categories = loadedCategories
        sortCategories()
    }
    
    private func saveUserCategories() {
        let userCategories = categories.filter { !$0.isPreset }
        if let data = try? JSONEncoder().encode(userCategories) {
            UserDefaults.standard.set(data, forKey: userDefaultsKey)
        }
    }
    
    private func savePresetColors() {
        let presetColors = categories
            .filter { $0.isPreset }
            .reduce(into: [String: String]()) { dict, cat in
                dict[cat.name] = cat.colorName
            }
        UserDefaults.standard.set(presetColors, forKey: presetColorsKey)
    }
    
    private func sortCategories() {
        // Presets first (in their defined order), then user categories alphabetically
        let presets = categories.filter { $0.isPreset }.sorted { cat1, cat2 in
            let idx1 = Category.defaultPresets.firstIndex(where: { $0.id == cat1.id }) ?? 0
            let idx2 = Category.defaultPresets.firstIndex(where: { $0.id == cat2.id }) ?? 0
            return idx1 < idx2
        }
        let userCats = categories.filter { !$0.isPreset }.sorted { $0.name < $1.name }
        categories = presets + userCats
    }
}

// MARK: - Preview Support

extension CategoryStore {
    static var preview: CategoryStore {
        let store = CategoryStore()
        store.addCategory(name: "Fitness", colorName: "green")
        store.addCategory(name: "Learning", colorName: "orange")
        return store
    }
}
