//
//  Requests.swift
//  TigerDine
//
//  Created by Campbell on 8/31/25.
//

import Foundation

enum InvalidHTTPError: Error {
    case invalid
}

// This code has now been mostly rewritten to be pretty and async instead of being horrifying callback based code in a context where
// callback based code made no sense. I love async!
// Get information for all dining locations.
func getAllDiningInfo(date: String?) async -> Result<DiningLocationsParser, Error> {
    // The endpoint requires that you specify a date, so get today's.
    let dateString: String = date ?? getTCAPIFriendlyDateString(date: Date())
    let urlString = "https://tigercenter.rit.edu/tigerCenterApi/tc/dining-all?date=\(dateString)"
    
    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            return .failure(InvalidHTTPError.invalid)
        }
        
        let decoded = try JSONDecoder().decode(DiningLocationsParser.self, from: data)
        return .success(decoded)
    } catch {
        return .failure(error)
    }
}

// Get information for just one dining location based on its location ID.
func getSingleDiningInfo(date: String?, locId: Int) async -> Result<DiningLocationParser, Error> {
    // The current date and the location ID are required to get information for just one location.
    let dateString: String = date ?? getTCAPIFriendlyDateString(date: Date())
    let urlString = "https://tigercenter.rit.edu/tigerCenterApi/tc/dining-single?date=\(dateString)&locId=\(locId)"
    print("making request to \(urlString)")

    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            return .failure(InvalidHTTPError.invalid)
        }
        
        let decoded = try JSONDecoder().decode(DiningLocationParser.self, from: data)
        return .success(decoded)
    } catch {
        return .failure(error)
    }
}

// Get the occupancy information for a location using its MDO ID, whatever that stands for. This ID is provided alongside the other
// main ID in the data returned by the TigerCenter API.
func getOccupancyPercentage(mdoId: Int) async -> Result<Double, Error> {
    let urlString = "https://maps.rit.edu/proxySearch/densityMapDetail.php?mdo=\(mdoId)"
    print("making request to \(urlString)")
    
    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }
    
    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            return .failure(InvalidHTTPError.invalid)
        }
        
        let occupancy = try JSONDecoder().decode([DiningOccupancyParser].self, from: data)
        if !occupancy.isEmpty {
            print("current occupancy: \(occupancy[0].count)")
            print("maximum occupancy: \(occupancy[0].max_occ)")
            let occupancyPercentage = Double(occupancy[0].count) / Double(occupancy[0].max_occ) * 100
            print("occupancy percentage: \(occupancyPercentage)%")
            return .success(occupancyPercentage)
        } else {
            return .failure(DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "Failed to decode JSON")))
        }
    } catch {
        return .failure(error)
    }
}

// Get the RIT Events food truck page and strip it down to just the part of the HTML that we'll need to parse with SwiftSoup.
func getFoodTruckPage() async -> Result<String, Error> {
    let urlString = "https://www.rit.edu/events/weekend-food-trucks"
    
    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    do {
        let contents = try String(contentsOf: url)
        let scheduleRegex = /<div class=\".*?field--name-field-event-description.*?\">([\s\S]*?)<\/div>/
        if let match = contents.firstMatch(of: scheduleRegex) {
            return .success(String(match.0))
        }
        return .success(contents)
    } catch {
        return .failure(error)
    }
}

func searchFDMealPlannerLocations() async -> Result<FDSearchResponseParser, Error> {
    let urlString = "https://locations.fdmealplanner.com/api/v1/location-data-webapi/search-locationByAccount?AccountShortName=RIT&pageIndex=1&pageSize=0"
    
    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            return .failure(InvalidHTTPError.invalid)
        }
        
        let decoded = try JSONDecoder().decode(FDSearchResponseParser.self, from: data)
        return .success(decoded)
    } catch {
        return .failure(error)
    }
}

func getFDMealPlannerOpenings(locationId: Int) async -> Result<FDMealPeriodsParser, Error> {
    let urlString = "https://apiservicelocatorstenantrit.fdmealplanner.com/api/v1/data-locator-webapi/20/mealPeriods?LocationId=\(locationId)"
    print("making request to \(urlString)")
    
    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            return .failure(InvalidHTTPError.invalid)
        }
        
        let decoded = try JSONDecoder().decode(FDMealPeriodsParser.self, from: data)
        return .success(decoded)
    } catch {
        return .failure(error)
    }
}

func getFDMealPlannerMenu(locationId: Int, accountId: Int, mealPeriodId: Int) async -> Result<FDMealsParser, Error> {
    let dateString = getFDMPAPIFriendlyDateString(date: Date())
    let urlString = "https://apiservicelocatorstenantrit.fdmealplanner.com/api/v1/data-locator-webapi/20/meals?menuId=0&accountId=\(accountId)&locationId=\(locationId)&mealPeriodId=\(mealPeriodId)&tenantId=20&monthId=\(Calendar.current.component(.month, from: Date()))&startDate=\(dateString)&endDate=\(dateString)"
    print("making request to \(urlString)")
    
    guard let url = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            return .failure(InvalidHTTPError.invalid)
        }
        
        let decoded = try JSONDecoder().decode(FDMealsParser.self, from: data)
        return .success(decoded)
    } catch {
        return .failure(error)
    }
}
