//
//  FDTDRDetails.swift
//  Product Calculator
//
//  Created by Suraj Kumar Mandal on 17/11/21.
//

import Foundation

// MARK: - FDTDRDetails
struct FDTDRDetails: Codable {
    let maturityDate, maturityDisplayDate : String?
    let interestReceived, totalInterestReceived : Int?
    let bankFdTdrLookupList: [FDTDRLookupList]?
    
    enum CodingKeys: String, CodingKey {
        case maturityDate = "maturityDate"
        case maturityDisplayDate = "maturityDisplayDate"
        case interestReceived = "interestReceived"
        case totalInterestReceived = "totalInterestReceived"
        case bankFdTdrLookupList = "bankFdTdrLookupList"
    }
}

// MARK: FDTDRDetails convenience initializers and mutators
extension FDTDRDetails {
    init(data: Data) throws {
        self = try newJSONDecoder().decode(FDTDRDetails.self, from: data)
    }
    
    init(_ json: String, using encoding: String.Encoding = .utf8) throws {
        guard let data = json.data(using: encoding) else {
            throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
        }
        try self.init(data: data)
    }
    
    init(fromURL url: URL) throws {
        try self.init(data: try Data(contentsOf: url))
    }
    
    func with(
        maturityDate: String?? = nil,
        maturityDisplayDate: String?? = nil,
        interestReceived: Int?? = nil,
        totalInterestReceived: Int?? = nil,
        bankFdTdrLookupList: [FDTDRLookupList]?? = nil
    ) -> FDTDRDetails {
        return FDTDRDetails(
            maturityDate: maturityDate ?? self.maturityDate,
            maturityDisplayDate: maturityDisplayDate ?? self.maturityDisplayDate,
            interestReceived: interestReceived ?? self.interestReceived,
            totalInterestReceived: totalInterestReceived ?? self.totalInterestReceived,
            bankFdTdrLookupList: bankFdTdrLookupList ?? self.bankFdTdrLookupList
        )
    }
    
    func jsonData() throws -> Data {
        return try newJSONEncoder().encode(self)
    }
    
    func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
        return String(data: try self.jsonData(), encoding: encoding)
    }
}

// MARK: - FDTDRLookupList
struct FDTDRLookupList: Codable {
    let serialNo, amountDeposited, interestReceived, interestAccrued, totalInterestAccrued, daysToMaturity : Int?
    let referenceDate, referenceMonth, financialYear : String?
    
    enum CodingKeys: String, CodingKey {
        case serialNo = "serialNo"
        case amountDeposited = "amountDeposited"
        case interestReceived = "interestReceived"
        case interestAccrued = "interestAccrued"
        case totalInterestAccrued = "totalInterestAccrued"
        case daysToMaturity = "daysToMaturity"
        case referenceDate = "referenceDate"
        case referenceMonth = "referenceMonth"
        case financialYear = "financialYear"
    }
}

// MARK: FDTDRLookupList convenience initializers and mutators
extension FDTDRLookupList {
    init(data: Data) throws {
        self = try newJSONDecoder().decode(FDTDRLookupList.self, from: data)
    }
    
    init(_ json: String, using encoding: String.Encoding = .utf8) throws {
        guard let data = json.data(using: encoding) else {
            throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
        }
        try self.init(data: data)
    }
    
    init(fromURL url: URL) throws {
        try self.init(data: try Data(contentsOf: url))
    }
    
    func with(
        serialNo: Int?? = nil,
        amountDeposited: Int?? = nil,
        interestReceived: Int?? = nil,
        interestAccrued: Int?? = nil,
        totalInterestAccrued: Int?? = nil,
        daysToMaturity: Int?? = nil,
        referenceDate: String?? = nil,
        referenceMonth: String?? = nil,
        financialYear: String?? = nil
        
        
    ) -> FDTDRLookupList {
        return FDTDRLookupList(
            serialNo: serialNo ?? self.serialNo,
            amountDeposited: amountDeposited ?? self.amountDeposited,
            interestReceived: interestReceived ?? self.interestReceived,
            interestAccrued: interestAccrued ?? self.interestAccrued,
            totalInterestAccrued: totalInterestAccrued ?? self.totalInterestAccrued,
            daysToMaturity: daysToMaturity ?? self.daysToMaturity,
            referenceDate: referenceDate ?? self.referenceDate,
            referenceMonth: referenceMonth ?? self.referenceMonth,
            financialYear: financialYear ?? self.financialYear
        )
    }
    
    func jsonData() throws -> Data {
        return try newJSONEncoder().encode(self)
    }
    
    func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
        return String(data: try self.jsonData(), encoding: encoding)
    }
}

// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> JSONDecoder {
    let decoder = JSONDecoder()
    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
        decoder.dateDecodingStrategy = .iso8601
    }
    return decoder
}

func newJSONEncoder() -> JSONEncoder {
    let encoder = JSONEncoder()
    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
        encoder.dateEncodingStrategy = .iso8601
    }
    return encoder
}
