package cmd

import (
	"context"
	"encoding/json"
	"fmt"
	"os"

	"gogs.dmsc.dev/arp/arp_cli/client"
	"gogs.dmsc.dev/arp/arp_cli/config"

	"github.com/AlecAivazis/survey/v2"
	"github.com/olekukonko/tablewriter"
	"github.com/urfave/cli/v3"
)

// PermissionCommand returns the permission command
func PermissionCommand() *cli.Command {
	return &cli.Command{
		Name:  "permission",
		Usage: "Manage permissions",
		Description: `Manage ARP permissions. Permissions define fine-grained access control.

Use this command to create, list, update, and delete permissions.`,
		Commands: []*cli.Command{
			{
				Name:    "list",
				Aliases: []string{"ls"},
				Usage:   "List all permissions",
				Flags: []cli.Flag{
					&cli.BoolFlag{
						Name:    "json",
						Aliases: []string{"j"},
						Usage:   "Output as JSON",
					},
				},
				Action: permissionList,
			},
			{
				Name:  "get",
				Usage: "Get a permission by ID",
				Flags: []cli.Flag{
					&cli.StringFlag{
						Name:     "id",
						Aliases:  []string{"i"},
						Usage:    "Permission ID",
						Required: true,
					},
					&cli.BoolFlag{
						Name:    "json",
						Aliases: []string{"j"},
						Usage:   "Output as JSON",
					},
				},
				Action: permissionGet,
			},
			{
				Name:   "create",
				Usage:  "Create a new permission",
				Action: permissionCreate,
				Flags: []cli.Flag{
					&cli.StringFlag{
						Name:    "code",
						Aliases: []string{"c"},
						Usage:   "Permission code",
					},
					&cli.StringFlag{
						Name:    "description",
						Aliases: []string{"d"},
						Usage:   "Permission description",
					},
				},
			},
			{
				Name:   "update",
				Usage:  "Update a permission",
				Action: permissionUpdate,
				Flags: []cli.Flag{
					&cli.StringFlag{
						Name:     "id",
						Aliases:  []string{"i"},
						Usage:    "Permission ID",
						Required: true,
					},
					&cli.StringFlag{
						Name:    "code",
						Aliases: []string{"c"},
						Usage:   "Permission code",
					},
					&cli.StringFlag{
						Name:    "description",
						Aliases: []string{"d"},
						Usage:   "Permission description",
					},
				},
			},
			{
				Name:   "delete",
				Usage:  "Delete a permission",
				Action: permissionDelete,
				Flags: []cli.Flag{
					&cli.StringFlag{
						Name:     "id",
						Aliases:  []string{"i"},
						Usage:    "Permission ID",
						Required: true,
					},
					&cli.BoolFlag{
						Name:    "yes",
						Aliases: []string{"y"},
						Usage:   "Skip confirmation",
					},
				},
			},
		},
	}
}

type PermissionDetail struct {
	ID          string `json:"id"`
	Code        string `json:"code"`
	Description string `json:"description"`
}

func permissionList(ctx context.Context, cmd *cli.Command) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}
	if err := RequireAuth(cfg); err != nil {
		return err
	}

	c := client.New(cfg.ServerURL)
	c.SetToken(cfg.Token)

	query := "query Permissions { permissions { id code description } }"

	resp, err := c.Query(query, nil)
	if err != nil {
		return err
	}

	var result struct {
		Permissions []PermissionDetail `json:"permissions"`
	}
	if err := json.Unmarshal(resp.Data, &result); err != nil {
		return err
	}

	if cmd.Bool("json") {
		enc := json.NewEncoder(os.Stdout)
		enc.SetIndent("", "  ")
		return enc.Encode(result.Permissions)
	}

	if len(result.Permissions) == 0 {
		fmt.Println("No permissions found.")
		return nil
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.Header([]string{"ID", "Code", "Description"})
	

	for _, p := range result.Permissions {
		table.Append([]string{p.ID, p.Code, p.Description})
	}

	table.Render()
	return nil
}

func permissionGet(ctx context.Context, cmd *cli.Command) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}
	if err := RequireAuth(cfg); err != nil {
		return err
	}

	c := client.New(cfg.ServerURL)
	c.SetToken(cfg.Token)

	id := cmd.String("id")
	query := "query Permission($id: ID!) { permission(id: $id) { id code description } }"

	resp, err := c.Query(query, map[string]interface{}{"id": id})
	if err != nil {
		return err
	}

	var result struct {
		Permission *PermissionDetail `json:"permission"`
	}
	if err := json.Unmarshal(resp.Data, &result); err != nil {
		return err
	}

	if result.Permission == nil {
		return fmt.Errorf("permission not found")
	}

	if cmd.Bool("json") {
		enc := json.NewEncoder(os.Stdout)
		enc.SetIndent("", "  ")
		return enc.Encode(result.Permission)
	}

	p := result.Permission
	fmt.Printf("ID: %s\n", p.ID)
	fmt.Printf("Code: %s\n", p.Code)
	fmt.Printf("Description: %s\n", p.Description)

	return nil
}

func permissionCreate(ctx context.Context, cmd *cli.Command) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}
	if err := RequireAuth(cfg); err != nil {
		return err
	}

	code := cmd.String("code")
	description := cmd.String("description")

	if code == "" {
		prompt := &survey.Input{Message: "Permission code:"}
		if err := survey.AskOne(prompt, &code, survey.WithValidator(survey.Required)); err != nil {
			return err
		}
	}

	if description == "" {
		prompt := &survey.Input{Message: "Description:"}
		if err := survey.AskOne(prompt, &description, survey.WithValidator(survey.Required)); err != nil {
			return err
		}
	}

	c := client.New(cfg.ServerURL)
	c.SetToken(cfg.Token)

	mutation := `mutation CreatePermission($input: NewPermission!) { createPermission(input: $input) { id code description } }`

	input := map[string]interface{}{
		"code":        code,
		"description": description,
	}

	resp, err := c.Mutation(mutation, map[string]interface{}{"input": input})
	if err != nil {
		return err
	}

	var result struct {
		CreatePermission *PermissionDetail `json:"createPermission"`
	}
	if err := json.Unmarshal(resp.Data, &result); err != nil {
		return err
	}

	if result.CreatePermission == nil {
		return fmt.Errorf("failed to create permission")
	}

	fmt.Printf("Permission created successfully!\n")
	fmt.Printf("ID: %s\n", result.CreatePermission.ID)
	fmt.Printf("Code: %s\n", result.CreatePermission.Code)

	return nil
}

func permissionUpdate(ctx context.Context, cmd *cli.Command) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}
	if err := RequireAuth(cfg); err != nil {
		return err
	}

	id := cmd.String("id")
	code := cmd.String("code")
	description := cmd.String("description")

	if code == "" && description == "" {
		fmt.Println("No updates provided. Use flags to specify what to update.")
		return nil
	}

	c := client.New(cfg.ServerURL)
	c.SetToken(cfg.Token)

	input := make(map[string]interface{})
	if code != "" {
		input["code"] = code
	}
	if description != "" {
		input["description"] = description
	}

	mutation := `mutation UpdatePermission($id: ID!, $input: UpdatePermissionInput!) { updatePermission(id: $id, input: $input) { id code description } }`

	resp, err := c.Mutation(mutation, map[string]interface{}{"id": id, "input": input})
	if err != nil {
		return err
	}

	var result struct {
		UpdatePermission *PermissionDetail `json:"updatePermission"`
	}
	if err := json.Unmarshal(resp.Data, &result); err != nil {
		return err
	}

	if result.UpdatePermission == nil {
		return fmt.Errorf("permission not found")
	}

	fmt.Printf("Permission updated successfully!\n")
	fmt.Printf("ID: %s\n", result.UpdatePermission.ID)
	fmt.Printf("Code: %s\n", result.UpdatePermission.Code)

	return nil
}

func permissionDelete(ctx context.Context, cmd *cli.Command) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}
	if err := RequireAuth(cfg); err != nil {
		return err
	}

	id := cmd.String("id")
	skipConfirm := cmd.Bool("yes")

	if !skipConfirm {
		confirm := false
		prompt := &survey.Confirm{
			Message: fmt.Sprintf("Are you sure you want to delete permission %s?", id),
			Default: false,
		}
		if err := survey.AskOne(prompt, &confirm); err != nil {
			return err
		}
		if !confirm {
			fmt.Println("Deletion cancelled.")
			return nil
		}
	}

	c := client.New(cfg.ServerURL)
	c.SetToken(cfg.Token)

	mutation := `mutation DeletePermission($id: ID!) { deletePermission(id: $id) }`

	resp, err := c.Mutation(mutation, map[string]interface{}{"id": id})
	if err != nil {
		return err
	}

	var result struct {
		DeletePermission bool `json:"deletePermission"`
	}
	if err := json.Unmarshal(resp.Data, &result); err != nil {
		return err
	}

	if result.DeletePermission {
		fmt.Printf("Permission %s deleted successfully.\n", id)
	} else {
		fmt.Printf("Failed to delete permission %s.\n", id)
	}

	return nil
}
