package main

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"text/tabwriter"
	"time"

	"git.warky.dev/wdevs/whatshooked/pkg/models"
	"git.warky.dev/wdevs/whatshooked/pkg/storage"
	resolvespec_common "github.com/bitechdev/ResolveSpec/pkg/spectypes"
	"github.com/google/uuid"
	"github.com/spf13/cobra"
)

var (
	accountUser        string
	accountPhoneNumber string
	accountType        string
	accountSessionPath string
	accountDisplayName string
)

var accountsCmd = &cobra.Command{
	Use:   "accounts",
	Short: "Manage WhatsApp accounts",
	Run: func(cmd *cobra.Command, args []string) {
		client := NewClient(cliConfig)
		listAccounts(client)
	},
}

var accountsListCmd = &cobra.Command{
	Use:   "list",
	Short: "List all accounts",
	Run: func(cmd *cobra.Command, args []string) {
		client := NewClient(cliConfig)
		listAccounts(client)
	},
}

var accountsAddCmd = &cobra.Command{
	Use:   "add",
	Short: "Add a new WhatsApp account",
	Run: func(cmd *cobra.Command, args []string) {
		client := NewClient(cliConfig)
		addAccount(client)
	},
}

var accountsRemoveCmd = &cobra.Command{
	Use:   "remove <id>",
	Short: "Remove a WhatsApp account by ID",
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		client := NewClient(cliConfig)
		removeAccount(client, args[0])
	},
}

func init() {
	accountsAddCmd.Flags().StringVarP(&accountPhoneNumber, "phone", "p", "", "Phone number (with country code)")
	accountsAddCmd.Flags().StringVarP(&accountType, "type", "t", "whatsmeow", "Account type (whatsmeow/business-api)")
	accountsAddCmd.Flags().StringVarP(&accountSessionPath, "session-path", "s", "", "Session path (auto-generated if omitted)")
	accountsAddCmd.Flags().StringVarP(&accountDisplayName, "display-name", "d", "", "Display name")
	accountsAddCmd.Flags().StringVarP(&accountUser, "user", "u", "", "Owner username for DB mode (default: first admin)")

	accountsCmd.AddCommand(accountsListCmd)
	accountsCmd.AddCommand(accountsAddCmd)
	accountsCmd.AddCommand(accountsRemoveCmd)
}

func listAccounts(client *Client) {
	if serverAvailable(client) {
		listAccountsHTTP(client)
	} else {
		fmt.Println("[server unavailable, reading from database]")
		if !tryInitDB() {
			fmt.Println("Error: server unreachable and no database config found. Use --server-config to specify config path.")
			return
		}
		listAccountsDB()
	}
}

func listAccountsHTTP(client *Client) {
	resp, err := client.Get("/api/accounts")
	checkError(err)
	defer resp.Body.Close()

	var accounts []map[string]interface{}
	checkError(decodeJSON(resp, &accounts))

	if len(accounts) == 0 {
		fmt.Println("No accounts configured")
		return
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "ID\tPHONE\tTYPE\tSTATUS\tACTIVE")
	for _, acc := range accounts {
		fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%v\n",
			acc["id"], acc["phone_number"], acc["account_type"], acc["status"], acc["active"])
	}
	w.Flush()
}

func listAccountsDB() {
	var accounts []models.ModelPublicWhatsappAccount
	err := storage.DB.NewSelect().Model(&accounts).OrderExpr("created_at ASC").Scan(context.Background())
	checkError(err)

	if len(accounts) == 0 {
		fmt.Println("No accounts configured")
		return
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "ID\tPHONE\tTYPE\tSTATUS\tACTIVE")
	for _, acc := range accounts {
		active := "yes"
		if !acc.Active {
			active = "no"
		}
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
			acc.ID.String(),
			acc.PhoneNumber.String(),
			acc.AccountType.String(),
			acc.Status.String(),
			active,
		)
	}
	w.Flush()
}

func addAccount(client *Client) {
	phone := accountPhoneNumber
	if phone == "" {
		phone = promptRequired("Phone Number (with country code)")
	}

	acctType := accountType
	if acctType == "" {
		acctType = promptLine("Account type (whatsmeow/business-api)", "whatsmeow")
	}

	displayName := accountDisplayName
	if displayName == "" {
		displayName = promptLine("Display name (optional)", "")
	}

	if serverAvailable(client) {
		addAccountHTTP(client, phone, acctType, displayName)
	} else {
		fmt.Println("[server unavailable, writing to database]")
		if !tryInitDB() {
			fmt.Println("Error: server unreachable and no database config found. Use --server-config to specify config path.")
			return
		}
		addAccountDB(phone, acctType, displayName)
	}
}

func addAccountHTTP(client *Client, phone, acctType, displayName string) {
	payload := map[string]interface{}{
		"phone_number": phone,
		"account_type": acctType,
		"display_name": displayName,
	}
	resp, err := client.Post("/api/accounts/add", payload)
	checkError(err)
	defer resp.Body.Close()
	fmt.Println("Account added successfully")
	fmt.Println("Check server logs for QR code to pair the device")
}

func addAccountDB(phone, acctType, displayName string) {
	userID := dbOwnerUserID(accountUser)
	if userID == "" {
		fmt.Println("Error: no users found in database. Create a user first with: users add")
		return
	}

	id := uuid.New().String()
	sessionPath := accountSessionPath
	if sessionPath == "" {
		sessionPath = fmt.Sprintf("./sessions/%s", id)
	}

	now := time.Now()
	var cfgJSON string
	if acctType == "business-api" {
		b, _ := json.Marshal(map[string]string{})
		cfgJSON = string(b)
	}

	account := &models.ModelPublicWhatsappAccount{
		ID:          resolvespec_common.NewSqlString(id),
		PhoneNumber: resolvespec_common.NewSqlString(phone),
		AccountType: resolvespec_common.NewSqlString(acctType),
		DisplayName: resolvespec_common.NewSqlString(displayName),
		SessionPath: resolvespec_common.NewSqlString(sessionPath),
		Config:      resolvespec_common.NewSqlString(cfgJSON),
		Status:      resolvespec_common.NewSqlString("disconnected"),
		UserID:      resolvespec_common.NewSqlString(userID),
		Active:      true,
		CreatedAt:   resolvespec_common.NewSqlTimeStamp(now),
		UpdatedAt:   resolvespec_common.NewSqlTimeStamp(now),
	}

	repo := storage.NewWhatsAppAccountRepository(storage.DB)
	checkError(repo.Create(context.Background(), account))

	fmt.Printf("Account '%s' added (ID: %s)\n", phone, id)
	fmt.Println("Start the server to connect and pair the device")
}

func removeAccount(client *Client, id string) {
	if serverAvailable(client) {
		resp, err := client.Post("/api/accounts/remove", map[string]string{"id": id})
		checkError(err)
		defer resp.Body.Close()
		fmt.Println("Account removed successfully")
	} else {
		fmt.Println("[server unavailable, removing from database]")
		if !tryInitDB() {
			fmt.Println("Error: server unreachable and no database config found. Use --server-config to specify config path.")
			return
		}
		repo := storage.NewWhatsAppAccountRepository(storage.DB)
		checkError(repo.Delete(context.Background(), id))
		fmt.Printf("Account '%s' removed\n", id)
	}
}

