// That work, you can pay. Fully functional
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/flosch/pongo2"
	"github.com/gofiber/fiber/v2"
	"github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/customer"
)

func PricingTableHandler(c *fiber.Ctx) error {
	return c.SendString(generatePricingTableChatHTML(c))
}

func generatePricingTableChatHTML(c *fiber.Ctx) string {
	var result User
	err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, "SELECT global currentUser { stripe_id, email } LIMIT 1;", &result)
	if err != nil {
		fmt.Println("Error getting user")
		panic(err)
	}

	clientSecretSession := CreateClientSecretSession(c)

	stripeTable := `
	<stripe-pricing-table 
	pricing-table-id="prctbl_1PJAxDP2nW0okNQyY0Q3mbg4"
	publishable-key="pk_live_51OxXuWP2nW0okNQyme1qdwbL535jbMmM1uIUi6U5zcvEUUwKraktmpCzudXNdPSTxlHpw2FbCtxpwbyFFcasQ7aj000tJJGpWW"
	customer-session-client-secret="` + clientSecretSession + `">
	</stripe-pricing-table>`

	closeBtn := `
	<div class="is-flex is-justify-content-flex-end">
	<a class="button is-small is-danger is-outlined" hx-get="/loadChat" hx-target="#chat-container" hx-swap="outerHTML"
	hx-trigger="click">
	<span class="icon">
	<i class="fa-solid fa-xmark"></i>
</span>
	</a>
	</div>`

	htmlString := "<div class='columns is-centered' id='chat-container'><div class='column is-12-mobile is-8-tablet is-6-desktop' id='chat-messages'>"

	NextMessages := []TemplateMessage{}
	nextMsg := TemplateMessage{
		Icon:    "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message
		Content: "<br>" + stripeTable + closeBtn,
		Hidden:  false, // Assuming Hidden is a field you want to include from Message
		Id:      "0",
		Name:    "JADE",
	}
	NextMessages = append(NextMessages, nextMsg)

	botOut, err := botTmpl.Execute(pongo2.Context{"Messages": NextMessages, "ConversationAreaId": 0, "NotClickable": true, "notFlex": true, "DontShowName": true})
	if err != nil {
		fmt.Println("Error executing template")
		panic(err)
	}
	htmlString += botOut
	htmlString += "<div style='height: 10px;'></div>"
	htmlString += "</div></div>"

	// Render the HTML template with the messages
	return htmlString
}

func CreateNewStripeCustomer(name string, email string) string {
	params := &stripe.CustomerParams{
		Name:  stripe.String(name),
		Email: stripe.String(email),
	}
	result, err := customer.New(params)
	if err != nil {
		panic(err)
	}
	return result.ID
}

func IsCurrentUserSubscribed(c *fiber.Ctx) (bool, bool) {
	var user User
	err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, "SELECT global currentUser { stripe_id } LIMIT 1;", &user)
	if err != nil {
		fmt.Println("Error getting user")
		panic(err)
	}
	result, err := customer.Get(user.StripeID, nil)
	if err != nil {
		fmt.Println("Error getting customer")
		panic(err)
	}
	if result.Subscriptions.TotalCount == 0 {
		return false, false
	}

	// Check if an active product "prod_PnDjBBwvQN36cQ" is in the subscription. It is the premium plan
	isPremium := false
	for _, sub := range result.Subscriptions.Data {
		if sub.Plan.Product.ID == "prod_Q9TpVos0t8QtX3" && sub.Plan.Active {
			isPremium = true
			break
		}
	}

	isBasic := false
	for _, sub := range result.Subscriptions.Data {
		if sub.Plan.Product.ID == "prod_QDHakyHUeHLMET" && sub.Plan.Active {
			isBasic = true
			break
		}
	}

	return isPremium, isBasic
}

func IsCurrentUserLimiteReached(c *fiber.Ctx, isBasic bool) bool {
	// 30 days ago
	date := time.Now().AddDate(0, 0, -30)
	// Count the number of Usage for the current user
	var count int64
	err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, `
	WITH
		U := (
			SELECT Usage
			FILTER .user = global currentUser AND .date >= <datetime>$0
		)
	SELECT count(U)
	`, &count, date)
	if err != nil {
		fmt.Println("Error counting Usage")
		panic(err)
	}
	// 500 if isBasic is false, otherwise 10000
	if isBasic {
		return count >= 4000
	} else {
		return count >= 200
	}
}

func CreateClientSecretSession(c *fiber.Ctx) string {
	var user User
	err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, "SELECT global currentUser { stripe_id } LIMIT 1;", &user)
	if err != nil {
		fmt.Println("Error getting user")
		panic(err)
	}

	url := "https://api.stripe.com/v1/customer_sessions"
	method := "POST"
	apiKey := stripe.Key

	payload := []byte(fmt.Sprintf("customer=%s&components[pricing_table][enabled]=true", user.StripeID))

	req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
	if err != nil {
		fmt.Println("failed to create request")
		panic(err)
	}
	req.Header.Add("Authorization", "Bearer "+apiKey)
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("failed to execute request")
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		fmt.Println("failed to create customer session")
		panic(fmt.Sprintf("failed to create customer session: %s", string(body)))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("failed to read response body")
		panic(err)
	}

	type CustomerSessionResponse struct {
		ClientSecret string `json:"client_secret"`
		CustomerID   string `json:"customer"`
	}

	var customerSession CustomerSessionResponse
	if err := json.Unmarshal(body, &customerSession); err != nil {
		fmt.Println("failed to unmarshal response")
		panic(err)
	}

	if user.StripeID != customerSession.CustomerID {
		panic("customer_id does not match")
	}

	return customerSession.ClientSecret
}
