package jitsi

import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"time"
)

// JitsiService handles Jitsi Meet integration for video conferences
type JitsiService struct {
	baseURL    string
	appID      string
	appSecret  string
	httpClient *http.Client
}

// Config holds Jitsi service configuration
type Config struct {
	BaseURL   string // e.g., "http://localhost:8443"
	AppID     string // Application ID for JWT (optional)
	AppSecret string // Secret for JWT signing (optional)
}

// NewJitsiService creates a new Jitsi service instance
func NewJitsiService(cfg Config) *JitsiService {
	return &JitsiService{
		baseURL:   strings.TrimSuffix(cfg.BaseURL, "/"),
		appID:     cfg.AppID,
		appSecret: cfg.AppSecret,
		httpClient: &http.Client{
			Timeout: 10 * time.Second,
		},
	}
}

// ========================================
// Types
// ========================================

// Meeting represents a Jitsi meeting configuration
type Meeting struct {
	RoomName    string            `json:"room_name"`
	DisplayName string            `json:"display_name,omitempty"`
	Email       string            `json:"email,omitempty"`
	Avatar      string            `json:"avatar,omitempty"`
	Subject     string            `json:"subject,omitempty"`
	Password    string            `json:"password,omitempty"`
	StartTime   *time.Time        `json:"start_time,omitempty"`
	Duration    int               `json:"duration,omitempty"` // in minutes
	Config      *MeetingConfig    `json:"config,omitempty"`
	Moderator   bool              `json:"moderator,omitempty"`
	Features    *MeetingFeatures  `json:"features,omitempty"`
}

// MeetingConfig holds Jitsi room configuration options
type MeetingConfig struct {
	StartWithAudioMuted bool `json:"start_with_audio_muted,omitempty"`
	StartWithVideoMuted bool `json:"start_with_video_muted,omitempty"`
	DisableDeepLinking  bool `json:"disable_deep_linking,omitempty"`
	RequireDisplayName  bool `json:"require_display_name,omitempty"`
	EnableLobby         bool `json:"enable_lobby,omitempty"`
	EnableRecording     bool `json:"enable_recording,omitempty"`
}

// MeetingFeatures controls which features are enabled
type MeetingFeatures struct {
	Livestreaming bool `json:"livestreaming,omitempty"`
	Recording     bool `json:"recording,omitempty"`
	Transcription bool `json:"transcription,omitempty"`
	OutboundCall  bool `json:"outbound_call,omitempty"`
}

// MeetingLink contains the generated meeting URL and metadata
type MeetingLink struct {
	URL          string     `json:"url"`
	RoomName     string     `json:"room_name"`
	JoinURL      string     `json:"join_url"`
	ModeratorURL string     `json:"moderator_url,omitempty"`
	Password     string     `json:"password,omitempty"`
	ExpiresAt    *time.Time `json:"expires_at,omitempty"`
	JWT          string     `json:"jwt,omitempty"`
}

// JWTClaims represents the JWT payload for Jitsi
type JWTClaims struct {
	Audience  string       `json:"aud,omitempty"`
	Issuer    string       `json:"iss,omitempty"`
	Subject   string       `json:"sub,omitempty"`
	Room      string       `json:"room,omitempty"`
	ExpiresAt int64        `json:"exp,omitempty"`
	NotBefore int64        `json:"nbf,omitempty"`
	Context   *JWTContext  `json:"context,omitempty"`
	Moderator bool         `json:"moderator,omitempty"`
	Features  *JWTFeatures `json:"features,omitempty"`
}

// JWTContext contains user information for JWT
type JWTContext struct {
	User   *JWTUser   `json:"user,omitempty"`
	Group  string     `json:"group,omitempty"`
	Callee *JWTCallee `json:"callee,omitempty"`
}

// JWTUser represents user info in JWT
type JWTUser struct {
	ID          string `json:"id,omitempty"`
	Name        string `json:"name,omitempty"`
	Email       string `json:"email,omitempty"`
	Avatar      string `json:"avatar,omitempty"`
	Moderator   bool   `json:"moderator,omitempty"`
	HiddenFromRecorder bool `json:"hidden-from-recorder,omitempty"`
}

// JWTCallee represents callee info (for 1:1 calls)
type JWTCallee struct {
	ID     string `json:"id,omitempty"`
	Name   string `json:"name,omitempty"`
	Avatar string `json:"avatar,omitempty"`
}

// JWTFeatures controls JWT-based feature access
type JWTFeatures struct {
	Livestreaming string `json:"livestreaming,omitempty"` // "true" or "false"
	Recording     string `json:"recording,omitempty"`
	Transcription string `json:"transcription,omitempty"`
	OutboundCall  string `json:"outbound-call,omitempty"`
}

// ScheduledMeeting represents a scheduled training/meeting
type ScheduledMeeting struct {
	ID          string     `json:"id"`
	Title       string     `json:"title"`
	Description string     `json:"description,omitempty"`
	RoomName    string     `json:"room_name"`
	HostID      string     `json:"host_id"`
	HostName    string     `json:"host_name"`
	StartTime   time.Time  `json:"start_time"`
	EndTime     time.Time  `json:"end_time"`
	Duration    int        `json:"duration"` // in minutes
	Password    string     `json:"password,omitempty"`
	MaxParticipants int    `json:"max_participants,omitempty"`
	Features    *MeetingFeatures `json:"features,omitempty"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
}

// ========================================
// Meeting Management
// ========================================

// CreateMeetingLink generates a meeting URL with optional JWT authentication
func (s *JitsiService) CreateMeetingLink(ctx context.Context, meeting Meeting) (*MeetingLink, error) {
	// Generate room name if not provided
	roomName := meeting.RoomName
	if roomName == "" {
		roomName = s.generateRoomName()
	}

	// Sanitize room name (Jitsi-compatible)
	roomName = s.sanitizeRoomName(roomName)

	link := &MeetingLink{
		RoomName: roomName,
		URL:      fmt.Sprintf("%s/%s", s.baseURL, roomName),
		JoinURL:  fmt.Sprintf("%s/%s", s.baseURL, roomName),
		Password: meeting.Password,
	}

	// Generate JWT if authentication is configured
	if s.appSecret != "" {
		jwt, expiresAt, err := s.generateJWT(meeting, roomName)
		if err != nil {
			return nil, fmt.Errorf("failed to generate JWT: %w", err)
		}
		link.JWT = jwt
		link.ExpiresAt = expiresAt
		link.JoinURL = fmt.Sprintf("%s/%s?jwt=%s", s.baseURL, roomName, jwt)

		// Generate moderator URL if user is moderator
		if meeting.Moderator {
			link.ModeratorURL = link.JoinURL
		}
	}

	// Add config parameters to URL
	if meeting.Config != nil {
		params := s.buildConfigParams(meeting.Config)
		if params != "" {
			separator := "?"
			if strings.Contains(link.JoinURL, "?") {
				separator = "&"
			}
			link.JoinURL += separator + params
		}
	}

	return link, nil
}

// CreateTrainingSession creates a meeting link optimized for training sessions
func (s *JitsiService) CreateTrainingSession(ctx context.Context, title string, hostName string, hostEmail string, duration int) (*MeetingLink, error) {
	meeting := Meeting{
		RoomName:    s.generateTrainingRoomName(title),
		DisplayName: hostName,
		Email:       hostEmail,
		Subject:     title,
		Duration:    duration,
		Moderator:   true,
		Config: &MeetingConfig{
			StartWithAudioMuted: true,  // Participants start muted
			StartWithVideoMuted: false, // Video on for training
			RequireDisplayName:  true,  // Know who's attending
			EnableLobby:         true,  // Waiting room
			EnableRecording:     true,  // Allow recording
		},
		Features: &MeetingFeatures{
			Recording:     true,
			Transcription: false,
		},
	}

	return s.CreateMeetingLink(ctx, meeting)
}

// CreateQuickMeeting creates a simple ad-hoc meeting
func (s *JitsiService) CreateQuickMeeting(ctx context.Context, displayName string) (*MeetingLink, error) {
	meeting := Meeting{
		DisplayName: displayName,
		Config: &MeetingConfig{
			StartWithAudioMuted: false,
			StartWithVideoMuted: false,
		},
	}

	return s.CreateMeetingLink(ctx, meeting)
}

// CreateParentTeacherMeeting creates a meeting for parent-teacher conferences
func (s *JitsiService) CreateParentTeacherMeeting(ctx context.Context, teacherName string, parentName string, studentName string, scheduledTime time.Time) (*MeetingLink, error) {
	roomName := fmt.Sprintf("elterngespraech-%s-%s",
		s.sanitizeRoomName(studentName),
		scheduledTime.Format("20060102-1504"))

	meeting := Meeting{
		RoomName:    roomName,
		DisplayName: teacherName,
		Subject:     fmt.Sprintf("Elterngespräch: %s", studentName),
		StartTime:   &scheduledTime,
		Duration:    30, // 30 minutes default
		Moderator:   true,
		Password:    s.generatePassword(),
		Config: &MeetingConfig{
			StartWithAudioMuted: false,
			StartWithVideoMuted: false,
			RequireDisplayName:  true,
			EnableLobby:         true, // Teacher admits parent
			DisableDeepLinking:  true,
		},
	}

	return s.CreateMeetingLink(ctx, meeting)
}

// CreateClassMeeting creates a meeting for an entire class
func (s *JitsiService) CreateClassMeeting(ctx context.Context, className string, teacherName string, subject string) (*MeetingLink, error) {
	roomName := fmt.Sprintf("klasse-%s-%s",
		s.sanitizeRoomName(className),
		time.Now().Format("20060102"))

	meeting := Meeting{
		RoomName:    roomName,
		DisplayName: teacherName,
		Subject:     fmt.Sprintf("%s - %s", className, subject),
		Moderator:   true,
		Config: &MeetingConfig{
			StartWithAudioMuted: true,  // Students muted by default
			StartWithVideoMuted: false,
			RequireDisplayName:  true,
			EnableLobby:         false, // Direct join for classes
		},
	}

	return s.CreateMeetingLink(ctx, meeting)
}

