package admin

import (
    "fmt"
    "net/http"
    "strings"

    "arimelody-web/controller"
    "arimelody-web/model"
)

func serveRelease(app *model.AppState) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        slices := strings.Split(r.URL.Path[1:], "/")
        releaseID := slices[0]

        session := r.Context().Value("session").(*model.Session)

        release, err := controller.GetRelease(app.DB, releaseID, true)
        if err != nil {
            if strings.Contains(err.Error(), "no rows") {
                http.NotFound(w, r)
                return
            }
            fmt.Printf("WARN: Failed to pull full release data for %s: %s\n", releaseID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        }

        if len(slices) > 1 {
            switch slices[1] {
            case "editcredits":
                serveEditCredits(release).ServeHTTP(w, r)
                return
            case "addcredit":
                serveAddCredit(app, release).ServeHTTP(w, r)
                return
            case "newcredit":
                serveNewCredit(app).ServeHTTP(w, r)
                return
            case "editlinks":
                serveEditLinks(release).ServeHTTP(w, r)
                return
            case "edittracks":
                serveEditTracks(release).ServeHTTP(w, r)
                return
            case "addtrack":
                serveAddTrack(app, release).ServeHTTP(w, r)
                return
            case "newtrack":
                serveNewTrack(app).ServeHTTP(w, r)
                return
            }
            http.NotFound(w, r)
            return
        }

        type ReleaseResponse struct {
            Session *model.Session
            Release *model.Release
        }

        err = releaseTemplate.Execute(w, ReleaseResponse{
            Session: session,
            Release: release,
        })
        if err != nil {
            fmt.Printf("Error rendering admin release page for %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    })
}

func serveEditCredits(release *model.Release) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/html")
        err := editCreditsTemplate.Execute(w, release)
        if err != nil {
            fmt.Printf("Error rendering edit credits component for %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    })
}

func serveAddCredit(app *model.AppState, release *model.Release) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        artists, err := controller.GetArtistsNotOnRelease(app.DB, release.ID)
        if err != nil {
            fmt.Printf("WARN: Failed to pull artists not on %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        }

        type response struct {
            ReleaseID   string;
            Artists     []*model.Artist
        }

        w.Header().Set("Content-Type", "text/html")
        err = addCreditTemplate.Execute(w, response{
            ReleaseID: release.ID,
            Artists: artists,
        })
        if err != nil {
            fmt.Printf("Error rendering add credits component for %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    })
}

func serveNewCredit(app *model.AppState) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        artistID := strings.Split(r.URL.Path, "/")[3]
        artist, err := controller.GetArtist(app.DB, artistID)
        if err != nil {
            fmt.Printf("WARN: Failed to pull artists %s: %s\n", artistID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        }
        if artist == nil {
            http.NotFound(w, r)
            return
        }

        w.Header().Set("Content-Type", "text/html")
        err = newCreditTemplate.Execute(w, artist)
        if err != nil {
            fmt.Printf("Error rendering new credit component for %s: %s\n", artist.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    })
}

func serveEditLinks(release *model.Release) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/html")
        err := editLinksTemplate.Execute(w, release)
        if err != nil {
            fmt.Printf("Error rendering edit links component for %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    })
}

func serveEditTracks(release *model.Release) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/html")

        type editTracksData struct {
            Release *model.Release
            Add func(a int, b int) int
        }

        err := editTracksTemplate.Execute(w, editTracksData{
            Release: release,
            Add: func(a, b int) int { return a + b },
        })
        if err != nil {
            fmt.Printf("Error rendering edit tracks component for %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    })
}

func serveAddTrack(app *model.AppState, release *model.Release) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        tracks, err := controller.GetTracksNotOnRelease(app.DB, release.ID)
        if err != nil {
            fmt.Printf("WARN: Failed to pull tracks not on %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        }

        type response struct {
            ReleaseID   string;
            Tracks      []*model.Track
        }

        w.Header().Set("Content-Type", "text/html")
        err = addTrackTemplate.Execute(w, response{
            ReleaseID: release.ID,
            Tracks: tracks,
        })
        if err != nil {
            fmt.Printf("Error rendering add tracks component for %s: %s\n", release.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
        return
    })
}

func serveNewTrack(app *model.AppState) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        trackID := strings.Split(r.URL.Path, "/")[3]
        track, err := controller.GetTrack(app.DB, trackID)
        if err != nil {
            fmt.Printf("Error rendering new track component for %s: %s\n", trackID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
            return
        }
        if track == nil {
            http.NotFound(w, r)
            return
        }

        w.Header().Set("Content-Type", "text/html")
        err = newTrackTemplate.Execute(w, track)
        if err != nil {
            fmt.Printf("Error rendering new track component for %s: %s\n", track.ID, err)
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
        return
    })
}
