//
//  SourceFileManager.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 01/03/2024.
//

import Foundation
import LeStorage

class SourceFileManager {
    static let shared = SourceFileManager()
    
    init() {
        createDirectoryIfNeeded()
    }
    
    let rankingSourceDirectory : URL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appending(path: "rankings")

    func createDirectoryIfNeeded() {
        let fileManager = FileManager.default
        do {
            let directoryURL = rankingSourceDirectory

            // Check if the directory exists
            if !fileManager.fileExists(atPath: directoryURL.path) {
                // Directory does not exist, create it
                try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
                print("Directory created at: \(directoryURL)")
            } else {
                print("Directory already exists at: \(directoryURL)")
            }
        } catch {
            print("Error: \(error)")
        }
    }
    
    var lastDataSource: String? {
        DataStore.shared.appSettings.lastDataSource
    }
    
    func lastDataSourceDate() -> Date? {
        guard let lastDataSource else { return nil }
        return URL.importDateFormatter.date(from: lastDataSource)
    }
    
    func fetchData() async {
        await fetchData(fromDate: Date())
//        if let mostRecent = mostRecentDateAvailable, let current = Calendar.current.date(byAdding: .month, value: 1, to: mostRecent), current > mostRecent {
//            await fetchData(fromDate: current)
//        } else {
//        }
    }
    
    func _removeAllData(fromDate current: Date) {
        let lastStringDate = URL.importDateFormatter.string(from: current)
        let files = ["MESSIEURS", "MESSIEURS-2", "MESSIEURS-3", "MESSIEURS-4", "DAMES"]
        files.forEach { fileName in
            NetworkManager.shared.removeRankingData(lastDateString: lastStringDate, fileName: fileName)
        }
    }
    
    func exportToCSV(players: [FederalPlayer], sourceFileType: SourceFile, date: Date) {
        let lastDateString = URL.importDateFormatter.string(from: date)
        let dateString = ["CLASSEMENT-PADEL", sourceFileType.rawValue,  lastDateString].joined(separator: "-") + "." + "csv"

        let documentsUrl:URL =  (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!
        let destinationFileUrl = documentsUrl.appendingPathComponent("\(dateString)")
        var csvText : String = ""
        for player in players {
            csvText.append(player.exportToCSV() + "\n")
        }
        
        do {
            try csvText.write(to: destinationFileUrl, atomically: true, encoding: .utf8)
            print("CSV file exported successfully.")
        } catch {
            print("Error writing CSV file:", error)
            Logger.error(error)
        }
    }

    func fetchData(fromDate current: Date) async {
        let lastStringDate = URL.importDateFormatter.string(from: current)

        let files = ["MESSIEURS", "MESSIEURS-2", "MESSIEURS-3", "MESSIEURS-4", "DAMES"]
        do {
            try await withThrowingTaskGroup(of: Void.self) { group in // Mark 1

                for file in files {
                    group.addTask {
                        try await NetworkManager.shared.downloadRankingData(lastDateString: lastStringDate, fileName: file)
                    }
                }

                try await group.waitForAll()
            }

//            if current < Date() {
//                if let nextCurrent = Calendar.current.date(byAdding: .month, value: 1, to: current) {
//                    await fetchData(fromDate: nextCurrent)
//                }
//            }
        } catch {
            print("downloadRankingData", error)
            
            if mostRecentDateAvailable == nil {
                if let previousDate = Calendar.current.date(byAdding: .month, value: -1, to: current) {
                    await fetchData(fromDate: previousDate)
                }
            }
        }

    }
    
    func getAllFiles(initialDate: String = "08-2022") async {
        let dates = monthsBetweenDates(startDateString: initialDate, endDateString: Date().monthYearFormatted)
            .compactMap {
                URL.importDateFormatter.date(from: $0)
            }
            .filter { date in
                allFiles.contains(where: { $0.dateFromPath == date }) == false
            }
        
        try? await dates.concurrentForEach { date in
            await self.fetchData(fromDate: date)
        }
    }
    
    func monthsBetweenDates(startDateString: String, endDateString: String) -> [String] {
        let dateFormatter = URL.importDateFormatter
        
        guard let startDate = dateFormatter.date(from: startDateString),
              let endDate = dateFormatter.date(from: endDateString) else {
            return []
        }
        
        var months: [String] = []
        var currentDate = startDate
        let calendar = Calendar.current
        
        while currentDate <= endDate {
            let monthString = dateFormatter.string(from: currentDate)
            months.append(monthString)
            
            guard let nextMonthDate = calendar.date(byAdding: .month, value: 1, to: currentDate) else {
                break
            }
            currentDate = nextMonthDate
        }
        return months
    }
    
    func getUnrankValue(forMale: Bool, rankSourceDate: Date?) -> Int? {
        let _rankSourceDate = rankSourceDate ?? mostRecentDateAvailable
        let urls = allFiles(forMale).filter { $0.dateFromPath == _rankSourceDate }
        return urls.compactMap { $0.getUnrankedValue() }.sorted().last
    }
    
    var mostRecentDateAvailable: Date? {
        allFiles(false).first?.dateFromPath
    }
    
    func removeAllFilesFromServer() {
        let allFiles = try! FileManager.default.contentsOfDirectory(at: rankingSourceDirectory, includingPropertiesForKeys: nil)
        allFiles.filter { $0.pathExtension == "csv" }.forEach { url in
            try? FileManager.default.removeItem(at: url)
        }
    }
    
    func jsonFiles() -> [URL] {
        let allJSONFiles = try! FileManager.default.contentsOfDirectory(at: rankingSourceDirectory, includingPropertiesForKeys: nil).filter({ url in
            url.pathExtension == "json"
        })
        return allJSONFiles
    }
    
    var allFiles: [URL] {
        let allFiles = try! FileManager.default.contentsOfDirectory(at: rankingSourceDirectory, includingPropertiesForKeys: nil).filter({ url in
            url.pathExtension == "csv"
        })
        
        return (allFiles + (Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil) ?? [])).sorted(by: \.dateFromPath).reversed()
    }
    
    func allFiles(_ isManPlayer: Bool) -> [URL] {
        allFiles.filter({ url in
            url.path().contains(isManPlayer ? SourceFile.messieurs.rawValue : SourceFile.dames.rawValue)
        })
    }
    
    func allFilesSortedByDate(_ isManPlayer: Bool) -> [URL] {
        return allFiles(isManPlayer)
    }
}

enum SourceFile: String, CaseIterable {
    case dames = "DAMES"
    case messieurs = "MESSIEURS"
    
    var filesFromServer: [URL] {
        let rankingSourceDirectory = SourceFileManager.shared.rankingSourceDirectory
        let allFiles = try! FileManager.default.contentsOfDirectory(at: rankingSourceDirectory, includingPropertiesForKeys: nil)
        return allFiles.filter{$0.pathExtension == "csv" && $0.path().contains(rawValue)}
    }
    
    var currentURLs: [URL] {
        var files = Bundle.main.urls(forResourcesWithExtension: "csv", subdirectory: nil)?.filter({ url in
            url.path().contains(rawValue)
        }) ?? []
        
        files.append(contentsOf: filesFromServer)
        
        if let mostRecent = files.sorted(by: \.dateFromPath).reversed().first {
            return files.filter({ $0.dateFromPath == mostRecent.dateFromPath })
        } else {
            return []
        }
    }
    
    var isMan: Bool {
        switch self {
        case .dames:
            return false
        default:
            return true
        }
    }
}
