package googleanalytics

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"
	"time"

	"github.com/wtfutil/wtf/utils"
	"golang.org/x/oauth2/google"
	gaV3 "google.golang.org/api/analytics/v3"
	gaV4 "google.golang.org/api/analyticsreporting/v4"
	"google.golang.org/api/option"
)

type websiteReport struct {
	Name           string
	Report         *gaV4.GetReportsResponse
	RealtimeReport *gaV3.RealtimeData
}

func (widget *Widget) Fetch() []websiteReport {
	secretPath, err := utils.ExpandHomeDir(widget.settings.secretFile)
	if err != nil {
		log.Fatalf("Unable to parse secretFile path")
	}

	serviceV4, err := makeReportServiceV4(secretPath)
	if err != nil {
		log.Fatalf("Unable to create v3 Google Analytics Reporting Service")
	}

	var serviceV3 *gaV3.Service
	if widget.settings.enableRealtime {
		serviceV3, err = makeReportServiceV3(secretPath)
		if err != nil {
			log.Fatalf("Unable to create v3 Google Analytics Reporting Service")
		}
	}

	visitorsDataArray := getReports(
		serviceV4, widget.settings.viewIds, widget.settings.months, serviceV3,
	)
	return visitorsDataArray
}

func buildNetClient(secretPath string) *http.Client {
	clientSecret, err := ioutil.ReadFile(filepath.Clean(secretPath))
	if err != nil {
		log.Fatalf("Unable to read secretPath. %v", err)
	}

	jwtConfig, err := google.JWTConfigFromJSON(clientSecret, gaV4.AnalyticsReadonlyScope)
	if err != nil {
		log.Fatalf("Unable to get config from JSON. %v", err)
	}

	return jwtConfig.Client(context.Background())
}

func makeReportServiceV3(secretPath string) (*gaV3.Service, error) {
	client := buildNetClient(secretPath)

	svc, err := gaV3.NewService(context.Background(), option.WithHTTPClient(client))
	if err != nil {
		log.Fatalf("Failed to create v3 Google Analytics Reporting Service")
	}

	return svc, err
}

func makeReportServiceV4(secretPath string) (*gaV4.Service, error) {
	client := buildNetClient(secretPath)
	svc, err := gaV4.NewService(context.Background(), option.WithHTTPClient(client))
	if err != nil {
		log.Fatalf("Failed to create v4 Google Analytics Reporting Service")
	}

	return svc, err
}

func getReports(
	serviceV4 *gaV4.Service, viewIds map[string]interface{}, displayedMonths int, serviceV3 *gaV3.Service,
) []websiteReport {
	startDate := fmt.Sprintf("%s-01", time.Now().AddDate(0, -displayedMonths+1, 0).Format("2006-01"))
	var websiteReports []websiteReport

	for website, viewID := range viewIds {
		// For custom queries: https://ga-dev-tools.appspot.com/dimensions-metrics-explorer/

		req := &gaV4.GetReportsRequest{
			ReportRequests: []*gaV4.ReportRequest{
				{
					ViewId: viewID.(string),
					DateRanges: []*gaV4.DateRange{
						{StartDate: startDate, EndDate: "today"},
					},
					Metrics: []*gaV4.Metric{
						{Expression: "ga:sessions"},
					},
					Dimensions: []*gaV4.Dimension{
						{Name: "ga:month"},
					},
				},
			},
		}
		response, err := serviceV4.Reports.BatchGet(req).Do()

		if err != nil {
			log.Fatalf("GET request to analyticsreporting/v4 returned error with viewID: %s", viewID)
		}
		if response.HTTPStatusCode != 200 {
			log.Fatalf("Did not get expected HTTP response code")
		}

		report := websiteReport{Name: website, Report: response}
		if serviceV3 != nil {
			report.RealtimeReport = getLiveCount(serviceV3, viewID.(string))
		}
		websiteReports = append(websiteReports, report)
	}
	return websiteReports
}

func getLiveCount(service *gaV3.Service, viewID string) *gaV3.RealtimeData {
	res, err := service.Data.Realtime.Get("ga:"+viewID, "rt:activeUsers").Do()
	if err != nil {
		log.Fatalf("Failed to fetch real time data for view ID %s: %v.  Have you enrolled in the real time beta?  If not, do so here: https://docs.google.com/forms/d/1qfRFysCikpgCMGqgF3yXdUyQW4xAlLyjKuOoOEFN2Uw/viewform", viewID, err)
	}

	return res
}
