//
//  ContentView.swift
//  gloss
//
//  Created by Saint on 10/23/22.
//

import SwiftUI
import GRDB
import GRDBQuery
import Introspect
import os

let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "network")

var currentId : String?
var currentOffset : CGFloat?

var gTracker: VisibilityTracker<String>?

// var curBook = "John"

extension UserDefaults {
    public func optionalInt(forKey defaultName: String) -> Int? {
        let defaults = self
        if let value = defaults.value(forKey: defaultName) {
            return value as? Int
        }
        return nil
    }

    public func optionalBool(forKey defaultName: String) -> Bool? {
        let defaults = self
        if let value = defaults.value(forKey: defaultName) {
            return value as? Bool
        }
        return nil
    }
}

struct BlueButtonStyle: ButtonStyle {
  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .font(.headline)
        .frame(width: 160)
        .contentShape(Rectangle())
        .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.black)
        .background(configuration.isPressed ? Color.purple.opacity(0.5) : Color.purple)
        .listRowBackground(configuration.isPressed ? Color.blue.opacity(0.5) : Color.black)
  }
}

func goToRibbon(selectedRibbon: Ribbon, 
                destRibbon: Ribbon, 
                scrollId: Binding<String?>,
                scrollOffset: Binding<CGFloat?>,
                refresh: Binding<Bool>,
                appDatabase: AppDatabase
                    ) {

                                                      Task {
    // @Binding var scrollId : String?
    // @Binding var scrollOffset : CGFloat?
    // @Binding var refresh : Bool
        // print("SELECTED RIBBON", selectedRibbon) 
        let userDefaults = UserDefaults.standard
        var scrollOffsetToSave = currentOffset
        var scrollIdToSave = currentId

        // Print("scrollOffsetToSave: ", scrollOffsetToSave)
        // Print("scrollIdToSave: ", scrollIdToSave)

        var updatedRibbon = selectedRibbon

        // scrollId = "10"
        // scrollOffset = CGFloat(100)
        // refresh.toggle()

        if (selectedRibbon.id != destRibbon.id!) {
            print("switching ribbons")

            scrollId.wrappedValue = destRibbon.scrollId
            // print("setting scroll offset")
            scrollOffset.wrappedValue = CGFloat(destRibbon.scrollOffset)
            // print(scrollOffset.wrappedValue)
            // print("end setting scroll offset")
            refresh.wrappedValue.toggle()

            //scrollId = "10"
            //scrollOffset = CGFloat(100)

            userDefaults.set(scrollId.wrappedValue, forKey: "currentId")
            userDefaults.set(scrollOffset.wrappedValue, forKey: "currentOffset")

            var updateSelectRibbon = SelectedRibbon(id: Int64(1), ribbonId: destRibbon.id!)
            // print("Saving selected ribbon")
            // print(updateSelectRibbon)
            do {
                _ = try await appDatabase.saveSelectedRibbon(&updateSelectRibbon)
            } catch  {
                // Print("something wrong")
            }
        }

        updatedRibbon.scrollOffset = Int(scrollOffsetToSave!)
        updatedRibbon.scrollId = scrollIdToSave!

        _ = try await appDatabase.saveRibbon(&updatedRibbon)
        // print("saved updatedRibbon", updatedRibbon)

        // print("UPDATED")
        scrollOffsetToSave = userDefaults.object(forKey: "currentOffset") as? CGFloat
        scrollIdToSave = userDefaults.object(forKey: "currentId") as? String

        // print("scrollOffsetToSave: ", scrollOffsetToSave)
        // print("scrollIdToSave: ", scrollIdToSave)
    }
}

struct SwitchButton : View {
    var ribbon: Ribbon
    @Binding var scrollId : String?
    @Binding var scrollOffset : CGFloat?
    @Binding var refresh : Bool

    @Environment(\.appDatabase) private var appDatabase

    @Query(SelectedRibbonRequest()) private var sr: [Ribbon]


    @State var saveOffset = CGFloat()
    var body: some View {
        // ForEach(sr) { selectedRibbon in 
        let ribbonString = String(sr[0].id!) + " " + String(ribbon.id!) + " " + String(ribbon.scrollOffset) + " " + ribbon.scrollId
        Button(ribbonString,
               action: {
                   Task {
                       goToRibbon(selectedRibbon: sr[0], 
                                  destRibbon: ribbon, 
                                  scrollId: $scrollId, 
                                  scrollOffset: $scrollOffset, 
                                  refresh: $refresh,
                                  appDatabase: appDatabase)
                   }
               }

        )
        .buttonStyle(BlueButtonStyle())
    }
    // }
}


// class ScrollViewHandler: NSObject {
//     public var scrollOffset =  CGFloat(10)
// }

// extension ScrollViewHandler: UIScrollViewDelegate {
//     func scrollViewDidScroll(_ scrollView: UIScrollView) {
//         scrollOffset = CGFloat(scrollView.contentOffset.y)
//         // print("delegate", scrollView.contentOffset.y)
//         // print("delegate prop", self.scrollOffset)
//     }
// }


class Verse: NSObject, Codable {
    var body: String
    var verse: Int
}

func makeVerseView(seg: SegDenorm) -> some View {
    var retView = Text("")
    var segSplit = seg.body.components(separatedBy: ";;")
    let decoder = JSONDecoder()
    segSplit.enumerated().forEach({ (index, item) in
        let verse = try! decoder.decode(Verse.self, from: item.data(using: .utf8)!)

        retView = retView + Text(String(verse.verse))
        .font(Font.custom("AveriaSerifLibre-Regular", size: 6))
        .baselineOffset(6.0)
        .foregroundColor(Color.white)

        retView = retView + Text(verse.body)
        .foregroundColor(Color.white)
        .font(Font.custom("AveriaSerifLibre-Regular", size: 15))
                                  })
    return retView
}

private struct SegRow: View {
    var seg: SegDenorm

    var body: some View {
        // makeVerseView(seg: seg)


        var retView = Text("")
        var segSplit = seg.body.components(separatedBy: ";;")
        let decoder = JSONDecoder()
        // Text(segSplit[0].body)
        // .id(seg.id)
        // VStack {
            // ForEach(segSplit.indices) { i in
            segSplit.enumerated().forEach({ (index, item) in
                let verse = try! decoder.decode(Verse.self, from: item.data(using: .utf8)!)

                var attributedString: AttributedString {
                    // var result = AttributedString("Hello World!")
                    var result = AttributedString(verse.body)
                    result.underlineStyle = Text.LineStyle(
                        pattern: .dot, color: .white)
                    return result
                }


                 retView = retView + Text(String(verse.verse))
                 //retView = retView + Text(attributedString)
                // Text(seg.body)
                // .contentShape(Rectangle())
                .font(Font.custom("AveriaSerifLibre-Regular", size: 10))
                .baselineOffset(6.0)
                .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))


                retView = retView + Text(attributedString)
                // .frame(maxWidth: .infinity, alignment: .leading)
                // .contentShape(Rectangle())
                .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
                .font(Font.custom("AveriaSerifLibre-Regular", size: 20))
                // .listRowBackground(Color(red: 0.2, green: 0.8, blue: 0.2))
                // .listRowInsets(EdgeInsets())
                // .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
                // .listRowSeparator(.hidden)
                // .id(String(seg.id) + "body" + String(i))
                // .id(seg.id)
                //.onTapGesture {
                //    selectedLine = seg.id
                   //Print(selectedLine)
                //}

                // .listRowBackground(Color(red: 0.2, green: 0.8, blue: 0.2))
                // .listRowInsets(EdgeInsets())
                // .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
                // .listRowSeparator(.hidden)
                // .id(String(seg.id) + "verse" + String(i))
                // .id(seg.id)
                //.onTapGesture {
                //    selectedLine = seg.id
                   //Print(selectedLine)
                //}
            })
         // }
        return retView
    }
}

struct ContentView: View {

    @State var viewState = CGSize.zero
    @State var pulledOut = CGSize.zero
    @State var taskTitle : String = "FIRST DOGGG"
    @State var curBook : String = "Matthew"
    @State var selectedLine : Int64? 

    @State var thisScrollView : UIScrollView?
    @State var scrollUpdate = false
    @State var initLoad = false

    // @State var currentId : String?
    // @State var currentOffset = CGFloat()

    // set this to scroll to area
    @State var scrollId : String?
    @State var scrollOffset:  CGFloat?

    @State var setScrollOffset:  CGFloat?


    @Query(SegDenormRequest(book: "bible.mark")) private var segs: [SegDenorm]

    // @State var scrollDelegate: ScrollViewHandler
    // @State var scrollDelegate = ScrollViewHandler()

    // @State var selectedRibbonId = Int64(UserDefaults.standard.optionalInt(forKey: "selectedRibbonId") ?? 1)

    // ribbon
    @Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]

    @State var endedDrag = true

    @State var readOffset = CGPoint()
   
    @State var refresh: Bool = false
    @State var refresh2: Bool = false


    @Query(RibbonRequest()) private var ribbons: [Ribbon]

    // @Query(RibbonRequest(id: Int64(UserDefaults.standard.optionalInt(forKey: "lastRibbonId") ?? 1))) private var selectedRibbon: [Ribbon]
    
    init() {
        UITableView.appearance().backgroundColor = UIColor(Color(red: 0.2, green: 0.2, blue: 0.2))
         // _selectedRibbon = Query(RibbonRequest(id: Int64(UserDefaults.standard.optionalInt(forKey: "lastRibbonId") ?? 1)))
        // self._scrollDelegate = State(initialValue: ScrollViewHandler())
    }
    
    var body: some View {
        // Print("rendering")

        var size1 = CGFloat(70)
        var size2 = CGFloat(120)
        var fontSize = CGFloat(20)
        GeometryReader { geometry in
            ZStack{
                VStack{
                    Text("MK")
                    .font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
                    .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
                    // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
                    .overlay( MyCustomShape().frame(width: size1, height: size1) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
                             // .foregroundColor(.white))
                    .frame(width: size2, height: size2)

                    Text("Ps")
                    .font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
                    .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
                    // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
                    .overlay( MyCustomShape().frame(width: size1, height: size1) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
                             // .foregroundColor(.white))
                    .frame(width: size1, height: size1)

                    Text("Jn")
                    .font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
                    .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
                    // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
                    .overlay( MyCustomShape().frame(width: size1, height: size1) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
                             // .foregroundColor(.white))
                    .frame(width: size1, height: size1)


                    // Text("MTW")
                    // .font(Font.custom("AveriaSerifLibre-Regular", size: 20))
                    // .foregroundColor(Color.white)
                    // .overlay( MyCustomShape().frame(width: 120, height: 100))
                    // .frame(width: 120, height: 120)


                    ForEach(ribbons) { ribbon in
                        SwitchButton(ribbon: ribbon,
                                     scrollId:$scrollId,
                                     scrollOffset:$scrollOffset,
                                     refresh:$refresh
                        )
                        .buttonStyle(BlueButtonStyle())
                        // Print("RIBBON")
                        // Print(ribbon)
                    }
                }
                .frame(width: geometry.size.width, height: geometry.size.height, alignment: .topLeading)
                .background(Color(red: 0.1, green: 0.1, blue: 0.1))

                ScrollViewReader { proxy in
                   VisibilityTrackingScrollView(action: handleVisibilityChanged) {
                        // ScrollView {

                            LazyVStack {
                                Text(refresh ? "Selected" : "not Selected")
                                Button("Jump to #8") {
                                    scrollId = "20"

                                }
                                ForEach(segs) { seg in
                                        SegRow(seg: seg)
                                        .id("\(seg.id)")
                                            
                                        .padding(EdgeInsets(top: 10, leading: 20, bottom: 40, trailing: 20))
                                       .trackVisibility(id: "\(seg.id)")
                                    
                                    // .onChange(of: geometry.frame(in: .named("scrollView"))) { imageRect in
                                        //Print(imageRect)
                                        //Print(outerProxy)
                                        // if isInView(innerRect: imageRect, isIn: outerProxy) {
                                        //     visibleIndex.insert(item)
                                        // } else {
                                        //     visibleIndex.remove(item)
                                        // }
                                    // }
                                }
                            }
                            .background(Color(red: 0.2, green: 0.2, blue: 0.2))
                        }
                        .onChange(of: refresh) { target in
                            //if let target = target {
                                //gTracker!.visibleViews["123123"] = CGFloat(100)
                                // Print("ON CHANGE", gTracker!.visibleViews)
                            // Print("removing", gTracker!.visibleViews.removeAll())

                                Print("first scroll to")
                                Print(scrollId)
                                proxy.scrollTo(scrollId! , anchor: .top)
                                currentId = scrollId!

                                Task {
                                    // try? await Task.sleep(nanoseconds: 1_000_000_000)


                                    // try? await Task.sleep(nanoseconds: 1_000_000_000)
                                    proxy.scrollTo(scrollId! , anchor: .top)

                                    DispatchQueue.main.async {
                                        // setScrollOffset = CGFloat(scrollOffset!)
                                        setScrollOffset = CGFloat(Int(currentOffset!) * -1 + Int(scrollOffset!))
                                        currentOffset = scrollOffset!

                                        refresh2.toggle()

                                    }
                                }
                            //}
                        }
                         .introspectScrollView { scrollView in
                             // Print("introspect")
                             // scrollView.delegate = scrollDelegate
                             //Print("Scroll delegate offset", scrollDelegate.scrollOffset)

                             if (setScrollOffset != nil) {
                                 // Print("Setting scroll offset in introspect", setScrollOffset)
                                 scrollView.contentOffset.y = scrollView.contentOffset.y + setScrollOffset!
                                 DispatchQueue.main.async { setScrollOffset = nil }
                             }

                             // if (thisScrollView == nil) {
                                 // Print("init scroll")
                             //     thisScrollView = scrollView
                             //     scrollView.contentOffset.y = CGFloat(selectedRibbon[0].scrollOffset)
                             // }
                         }
                        .listStyle(PlainListStyle())
                }
                .background(Color(red: 0.2, green: 0.2, blue: 0.2))
                .frame(width: geometry.size.width - 50)
                .offset(x:30 , y:0)
                .offset(x: pulledOut.width)
                .offset(x: viewState.width, y: viewState.height)
                .gesture(
                    DragGesture()
                    .onChanged { gesture in

                        if (endedDrag) {
                            endedDrag = false
                            scrollOffset = readOffset.y - 20
                            // _ = Print("meow")
                        }
                        // logger.error("hello222")
                        // NSLog("hellooo")
                        Print(viewState.width)
                        if (abs(gesture.translation.width) > 20) {
                            viewState.width = gesture.translation.width
                        }
                        //offset.y = gesture.translation.width
                        // logger.log("hello")
                    }
                    .onEnded { _ in
                        endedDrag = true
                        var pulledOutWidth = CGFloat(0)
                        if (viewState.width < 0) {
                            pulledOutWidth = CGFloat(0)
                        }
                        else if abs(viewState.width + pulledOut.width ) > 30 {
                            pulledOutWidth = CGFloat(200)
                        } 

                        withAnimation(.spring(response: 0.2)) {
                            pulledOut.width = pulledOutWidth
                            viewState = .zero
                        }
                    }
                )
            }
        }
    }

    func handleVisibilityChanged(_ id: String, change: VisibilityChange, tracker: VisibilityTracker<String>) {


        // @Environment(\.appDatabase) var appDatabase
        // switch change {
        //     case .shown: print("\(id) shown")
        //     case .hidden: print("\(id) hidden")
        // }
        // print("VISIBILITY CHANGED STARTED")
        // print(tracker.visibleViews)
        // gTracker = tracker
        // print(tracker.sortedViewIDs)
        // print("VISIBILITY CHANGED ENDED")
        // if (currentId != nil) { 
        //     currentOffset = tracker.visibleViews[currentId!]!
        // }

        let visibleViews2 = Array(tracker.visibleViews.keys)
        if (visibleViews2.count == 0) { 

            return
        }

        currentId = tracker.sortedViewIDs[0]
        if (currentId != nil) {
            print("current ID:", currentId)

            // Access Shared Defaults Object
            // let userDefaults = UserDefaults.standard

            // Write/Set Value
            // Print(currentId!)
            // Print(tracker.visibleViews[currentId?]!)
            // userDefaults.set(currentId, forKey: "currentId")
            // userDefaults.set(tracker.visibleViews[currentId]!, forKey: "currentOffset")
            currentOffset = tracker.visibleViews[currentId!]!
            // userDefaults.set(tracker.visibleViews[currentId!]!, forKey: "currentOffset")
            // var updateScrollState = ScrollState(id: Int64(1), 
            //                                     scrollId: currentId!,
            //                                     scrollOffset: Int64(tracker.visibleViews[currentId!]!))
            // Print("Savingg")
            //Print(updateScrollState)
            // Task(priority: .default) {

            //     do {
            //         _ = try await appDatabase.saveScrollState(&updateScrollState)

        //     } catch  {
                    // Print("something wrong")
            //     }
            // }
        }

                                // gTracker!.visibleViews.removeAll()
    }
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .medium
    return formatter
}()

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()

        ContentView().environment(\.appDatabase, .random())
    }
}

extension View {
    func Print(_ vars: Any...) -> some View {
        for v in vars { print(v) }
        return EmptyView()
    }
}
