package voice

import (
	"context"
	"fmt"
	"time"

	"github.com/livekit/protocol/auth"
	"github.com/livekit/protocol/livekit"
	lksdk "github.com/livekit/server-sdk-go/v2"
)

type Client struct {
	apiKey     string
	apiSecret  string
	url        string
	roomClient *lksdk.RoomServiceClient
}

func NewClient(apiKey, apiSecret, url string) *Client {
	if apiKey == "" || apiSecret == "" {
		return nil
	}

	roomClient := lksdk.NewRoomServiceClient(url, apiKey, apiSecret)

	return &Client{
		apiKey:     apiKey,
		apiSecret:  apiSecret,
		url:        url,
		roomClient: roomClient,
	}
}

func (c *Client) GenerateToken(roomName, participantID, identity string) (string, error) {
	if c == nil {
		return "", fmt.Errorf("voice client not configured")
	}

	at := auth.NewAccessToken(c.apiKey, c.apiSecret)
	grant := &auth.VideoGrant{
		RoomJoin:     true,
		Room:         roomName,
		CanPublish:   boolPtr(true),
		CanSubscribe: boolPtr(true),
	}
	at.SetVideoGrant(grant)
	at.SetIdentity(identity)
	at.SetValidFor(time.Hour)

	token, err := at.ToJWT()
	if err != nil {
		return "", fmt.Errorf("generate token: %w", err)
	}

	return token, nil
}

func (c *Client) CreateRoom(name string) (*livekit.Room, error) {
	if c == nil {
		return nil, fmt.Errorf("voice client not configured")
	}

	room, err := c.roomClient.CreateRoom(context.Background(), &livekit.CreateRoomRequest{
		Name:            name,
		EmptyTimeout:    300, // 5 minutes before auto-delete when empty
		MaxParticipants: 20,
	})
	if err != nil {
		return nil, fmt.Errorf("create room: %w", err)
	}

	return room, nil
}

func (c *Client) DeleteRoom(name string) error {
	if c == nil {
		return fmt.Errorf("voice client not configured")
	}

	_, err := c.roomClient.DeleteRoom(context.Background(), &livekit.DeleteRoomRequest{
		Room: name,
	})
	return err
}

func (c *Client) ListParticipants(roomName string) ([]*livekit.ParticipantInfo, error) {
	if c == nil {
		return nil, fmt.Errorf("voice client not configured")
	}

	resp, err := c.roomClient.ListParticipants(context.Background(), &livekit.ListParticipantsRequest{
		Room: roomName,
	})
	if err != nil {
		return nil, fmt.Errorf("list participants: %w", err)
	}

	return resp.Participants, nil
}

func (c *Client) MuteParticipant(roomName string, identity string) error {
	if c == nil {
		return fmt.Errorf("voice client not configured")
	}

	participant, err := c.roomClient.GetParticipant(context.Background(), &livekit.RoomParticipantIdentity{
		Room:     roomName,
		Identity: identity,
	})
	if err != nil {
		return fmt.Errorf("get participant: %w", err)
	}

	for _, track := range participant.Tracks {
		_, err := c.roomClient.MutePublishedTrack(context.Background(), &livekit.MuteRoomTrackRequest{
			Room:     roomName,
			Identity: identity,
			TrackSid: track.Sid,
			Muted:    true,
		})
		if err != nil {
			return fmt.Errorf("mute track %s: %w", track.Sid, err)
		}
	}
	return nil
}

func boolPtr(b bool) *bool {
	return &b
}
