// SPDX-FileCopyrightText: 2026 Brent Daignault
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation

// ── Member ───────────────────────────────────────────────────────────────────
//
// CSV schema (10 fields, header row skipped):
//   type, first, last, address, city, pcode, ph1, ph2, email1, email2

struct Member {
    var type = ""
    var first = ""
    var last = ""
    var address = ""
    var city = ""
    var pcode = ""
    var ph1 = ""
    var ph2 = ""
    var email1 = ""
    var email2 = ""
}

enum MemberCategory {
    case caller, cuer, member, newDancer, unknown
}

extension Member {
    var category: MemberCategory {
        switch type.lowercased() {
        case "caller":     return .caller
        case "cuer":       return .cuer
        case "member":     return .member
        case "new dancer": return .newDancer
        default:           return .unknown
        }
    }
}

/// Sorts alphabetically by last name, then first name (case-insensitive).
func sortedByLastFirst(_ members: [Member]) -> [Member] {
    members.sorted { a, b in
        let lastCompare = a.last.localizedCaseInsensitiveCompare(b.last)
        if lastCompare != .orderedSame {
            return lastCompare == .orderedAscending
        }
        return a.first.localizedCaseInsensitiveCompare(b.first) == .orderedAscending
    }
}

// ── CSV parsing ──────────────────────────────────────────────────────────────

enum CSVParser {
    /// Parses one CSV line, handling double-quoted fields with "" escapes.
    static func parseLine(_ line: String) -> [String] {
        var fields: [String] = []
        var current = ""
        var inQuotes = false
        let chars = Array(line)
        var i = 0

        while i < chars.count {
            let c = chars[i]
            if inQuotes {
                if c == "\"" {
                    if i + 1 < chars.count, chars[i + 1] == "\"" {
                        current.append("\"")
                        i += 2
                    } else {
                        inQuotes = false
                        i += 1
                    }
                } else {
                    current.append(c)
                    i += 1
                }
            } else if c == "\"" {
                inQuotes = true
                i += 1
            } else if c == "," {
                fields.append(current.trimmingCharacters(in: .whitespaces))
                current = ""
                i += 1
            } else {
                current.append(c)
                i += 1
            }
        }
        fields.append(current.trimmingCharacters(in: .whitespaces))
        return fields
    }

    /// Loads and parses a member CSV file, skipping the header row.
    /// Rows with fewer than 7 fields (through ph1) are skipped.
    static func loadMembers(from path: String) throws -> [Member] {
        let url = URL(fileURLWithPath: path)
        let text = try String(contentsOf: url, encoding: .utf8)

        var lines = text.components(separatedBy: .newlines)
        lines.removeAll { $0.isEmpty }
        guard !lines.isEmpty else { return [] }
        lines.removeFirst()   // header row

        var members: [Member] = []
        for line in lines {
            let f = parseLine(line)
            guard f.count >= 7 else { continue }
            var m = Member()
            m.type    = f[0]
            m.first   = f[1]
            m.last    = f[2]
            m.address = f[3]
            m.city    = f[4]
            m.pcode   = f[5]
            m.ph1     = f[6]
            if f.count > 7 { m.ph2     = f[7] }
            if f.count > 8 { m.email1  = f[8] }
            if f.count > 9 { m.email2  = f[9] }
            members.append(m)
        }
        return members
    }
}
