import Foundation

// MARK: - Suggestion Feedback

enum SuggestionFeedback: String, Codable {
    case didIt          // "Success!" then any reflection
    case skipped        // "Next Time"
    case dismissed      // "Don't Suggest" (removed from pool)
}

enum WellnessReflection: String, Codable {
    case great      // "Feeling Great"
    case same       // "About the Same"
    case notReally  // "Not Really"
}

// MARK: - Work Log Entry

struct WorkLogEntry: Codable, Identifiable {
    let id: UUID
    let date: Date
    let durationSeconds: Int
    let intent: String?
    let completed: Bool
    let reflection: String?
    let additionalNotes: String?
    let suggestion: String?
    let suggestionFeedback: SuggestionFeedback?
    let wellnessReflection: WellnessReflection?

    init(
        id: UUID = UUID(),
        date: Date,
        durationSeconds: Int,
        intent: String?,
        completed: Bool,
        reflection: String?,
        additionalNotes: String?,
        suggestion: String? = nil,
        suggestionFeedback: SuggestionFeedback? = nil,
        wellnessReflection: WellnessReflection? = nil
    ) {
        self.id = id
        self.date = date
        self.durationSeconds = durationSeconds
        self.intent = intent
        self.completed = completed
        self.reflection = reflection
        self.additionalNotes = additionalNotes
        self.suggestion = suggestion
        self.suggestionFeedback = suggestionFeedback
        self.wellnessReflection = wellnessReflection
    }
}

// MARK: - Work Log Store

class WorkLogStore {
    static let shared = WorkLogStore()

    private let key = "pommedoro.workLog"
    private let defaults = UserDefaults.standard
    private let encoder = JSONEncoder()
    private let decoder = JSONDecoder()

    private var lastLoggedDay: String?

    private(set) var entries: [WorkLogEntry] = []

    private static var workLogFileURL: URL {
        let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
        return support
            .appendingPathComponent("Pommedoro", isDirectory: true)
            .appendingPathComponent("worklog.log", isDirectory: false)
    }

    private init() {
        load()
        clearOldEntries()
        migrateFromDocumentsIfNeeded()
    }

    /// One-time migration: move worklog.log from ~/Documents/pommedoro/ to Application Support
    private func migrateFromDocumentsIfNeeded() {
        let oldFile = FileManager.default.homeDirectoryForCurrentUser
            .appendingPathComponent("Documents", isDirectory: true)
            .appendingPathComponent("pommedoro", isDirectory: true)
            .appendingPathComponent("worklog.log", isDirectory: false)
        guard FileManager.default.fileExists(atPath: oldFile.path) else { return }

        ensureWorkLogDirectory()
        let newFile = Self.workLogFileURL

        // If new file doesn't exist yet, just move it; otherwise append old content
        if !FileManager.default.fileExists(atPath: newFile.path) {
            try? FileManager.default.moveItem(at: oldFile, to: newFile)
        } else if let oldData = try? Data(contentsOf: oldFile),
                  let handle = try? FileHandle(forWritingTo: newFile) {
            handle.seekToEndOfFile()
            handle.write(oldData)
            try? handle.close()
            try? FileManager.default.removeItem(at: oldFile)
        }

        // Clean up empty old directory
        let oldDir = oldFile.deletingLastPathComponent()
        let remaining = (try? FileManager.default.contentsOfDirectory(atPath: oldDir.path)) ?? []
        if remaining.isEmpty {
            try? FileManager.default.removeItem(at: oldDir)
        }
    }

    func addEntry(_ entry: WorkLogEntry) {
        entries.append(entry)
        save()
        appendEntryToFile(entry)
    }

    func todayEntries() -> [WorkLogEntry] {
        let calendar = Calendar.current
        return entries.filter { calendar.isDateInToday($0.date) }
    }

    func lastTodayIntent() -> String? {
        return todayEntries().last(where: { $0.intent != nil && !$0.intent!.isEmpty })?.intent
    }

    func todaySummary() -> (intervals: Int, totalSeconds: Int) {
        let today = todayEntries()
        let total = today.reduce(0) { $0 + $1.durationSeconds }
        return (intervals: today.count, totalSeconds: total)
    }

    func todayLogAsText() -> String {
        formatEntriesAsText(todayEntries(), includeDaySeparator: false)
    }

    private func save() {
        guard let data = try? encoder.encode(entries) else { return }
        defaults.set(data, forKey: key)
    }

    private func load() {
        guard let data = defaults.data(forKey: key),
              let decoded = try? decoder.decode([WorkLogEntry].self, from: data) else {
            entries = []
            return
        }
        entries = decoded
    }

    func clearOldEntries() {
        let cutoff = Calendar.current.date(byAdding: .day, value: -7, to: Date()) ?? Date()
        let before = entries.count
        entries.removeAll { $0.date < cutoff }
        if entries.count != before { save() }
    }

    private func ensureWorkLogDirectory() {
        let dir = Self.workLogFileURL.deletingLastPathComponent()
        try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
    }

    private static let isoFormatter: ISO8601DateFormatter = {
        let f = ISO8601DateFormatter()
        f.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        f.timeZone = TimeZone.current
        return f
    }()

    private static let dayFormatter: DateFormatter = {
        let f = DateFormatter()
        f.dateFormat = "yyyy-MM-dd"
        f.timeZone = TimeZone.current
        return f
    }()

    private func appendEntryToFile(_ entry: WorkLogEntry) {
        ensureWorkLogDirectory()
        let dayStr = Self.dayFormatter.string(from: entry.date)
        var lines: [String] = []

        if lastLoggedDay != dayStr {
            if lastLoggedDay != nil { lines.append("") }
            lines.append("--- \(dayStr) ---")
            lastLoggedDay = dayStr
        }

        let iso = Self.isoFormatter.string(from: entry.date)
        let durMins = entry.durationSeconds / 60
        let status = entry.completed ? "completed" : "partial"
        let intentPart = entry.intent.map { "  intent: \(flattenForLog($0))" } ?? ""
        let reflPart = entry.reflection.map { "  reflection: \(flattenForLog($0))" } ?? ""
        let suggPart = entry.suggestion.map { "  suggestion: \(flattenForLog($0))" } ?? ""
        let fbPart = entry.suggestionFeedback.map { "  feedback: \($0.rawValue)" } ?? ""
        let wellPart = entry.wellnessReflection.map { "  wellness: \($0.rawValue)" } ?? ""
        lines.append("\(iso)  \(durMins)m  \(status)\(intentPart)\(reflPart)\(suggPart)\(fbPart)\(wellPart)")

        guard let data = (lines.joined(separator: "\n") + "\n").data(using: .utf8) else { return }
        if let handle = try? FileHandle(forWritingTo: Self.workLogFileURL) {
            handle.seekToEndOfFile()
            handle.write(data)
            try? handle.close()
        } else {
            try? data.write(to: Self.workLogFileURL)
        }
    }

    private func flattenForLog(_ s: String) -> String {
        s.replacingOccurrences(of: "\n", with: " ")
            .replacingOccurrences(of: "\t", with: " ")
            .trimmingCharacters(in: .whitespaces)
    }

    private func formatEntriesAsText(_ entries: [WorkLogEntry], includeDaySeparator: Bool) -> String {
        guard !entries.isEmpty else {
            return "No intervals logged yet today."
        }
        var parts: [String] = []
        var currentDay: String?
        for entry in entries {
            let dayStr = Self.dayFormatter.string(from: entry.date)
            if includeDaySeparator, currentDay != dayStr {
                if currentDay != nil { parts.append("") }
                parts.append("--- \(dayStr) ---")
                currentDay = dayStr
            } else if !includeDaySeparator {
                currentDay = dayStr
            }
            let iso = Self.isoFormatter.string(from: entry.date)
            let durMins = entry.durationSeconds / 60
            let status = entry.completed ? "completed" : "partial"
            var line = "\(iso)  \(durMins)m  \(status)"
            if let i = entry.intent, !i.isEmpty { line += "  intent: \(flattenForLog(i))" }
            if let r = entry.reflection, !r.isEmpty { line += "  reflection: \(flattenForLog(r))" }
            if let s = entry.suggestion, !s.isEmpty { line += "  suggestion: \(flattenForLog(s))" }
            if let fb = entry.suggestionFeedback { line += "  feedback: \(fb.rawValue)" }
            if let w = entry.wellnessReflection { line += "  wellness: \(w.rawValue)" }
            parts.append(line)
        }
        return parts.joined(separator: "\n")
    }
}
