package services

import (
	"context"
	"database/sql"
	"fmt"
	"time"
)

type ChatService struct {
	DB       *sql.DB
	Appwrite *AppwriteService
}

func NewChatService(db *sql.DB, appwrite *AppwriteService) *ChatService {
	return &ChatService{
		DB:       db,
		Appwrite: appwrite,
	}
}

type Message struct {
	ID             string    `json:"id"`
	ConversationID string    `json:"conversationId"`
	SenderID       string    `json:"senderId"`
	Content        string    `json:"content"`
	CreatedAt      time.Time `json:"createdAt"`
	IsMine         bool      `json:"isMine"` // Populated by handler/frontend logic
}

type Conversation struct {
	ID                string     `json:"id"`
	CandidateID       string     `json:"candidateId"`
	CompanyID         string     `json:"companyId"`
	JobID             *string    `json:"jobId"`
	LastMessage       *string    `json:"lastMessage"`
	LastMessageAt     *time.Time `json:"lastMessageAt"`
	ParticipantName   string     `json:"participantName"`
	ParticipantAvatar string     `json:"participantAvatar"`
	UnreadCount       int        `json:"unreadCount"`
}

func (s *ChatService) SendMessage(ctx context.Context, senderID, conversationID, content string) (*Message, error) {
	// 1. Insert into Postgres
	var msgID string
	var createdAt time.Time
	query := `
		INSERT INTO messages (conversation_id, sender_id, content)
		VALUES ($1, $2, $3)
		RETURNING id, created_at
	`
	err := s.DB.QueryRowContext(ctx, query, conversationID, senderID, content).Scan(&msgID, &createdAt)
	if err != nil {
		return nil, fmt.Errorf("failed to insert message: %w", err)
	}

	// 2. Update Conversation (async-ish if needed, but important for sorting)
	updateQuery := `
		UPDATE conversations 
		SET last_message = $1, last_message_at = $2, updated_at = $2
		WHERE id = $3
	`
	if _, err := s.DB.ExecContext(ctx, updateQuery, content, createdAt, conversationID); err != nil {
		// Log error but assume message is sent
		fmt.Printf("Failed to update conversation: %v\n", err)
	}

	// 3. Push to Appwrite
	go func() {
		// Fire and forget for realtime
		err := s.Appwrite.PushMessage(context.Background(), msgID, conversationID, senderID, content)
		if err != nil {
			fmt.Printf("Appwrite push failed: %v\n", err)
		}
	}()

	return &Message{
		ID:             msgID,
		ConversationID: conversationID,
		SenderID:       senderID,
		Content:        content,
		CreatedAt:      createdAt,
	}, nil
}

func (s *ChatService) ListMessages(ctx context.Context, conversationID string) ([]Message, error) {
	query := `
		SELECT id, conversation_id, sender_id, content, created_at
		FROM messages
		WHERE conversation_id = $1
		ORDER BY created_at ASC
	`
	rows, err := s.DB.QueryContext(ctx, query, conversationID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var msgs []Message
	for rows.Next() {
		var m Message
		if err := rows.Scan(&m.ID, &m.ConversationID, &m.SenderID, &m.Content, &m.CreatedAt); err != nil {
			return nil, err
		}
		msgs = append(msgs, m)
	}
	return msgs, nil
}

// ListConversations lists conversations for a user (candidate or company admin)
func (s *ChatService) ListConversations(ctx context.Context, userID, tenantID string, isCandidate bool) ([]Conversation, error) {
	var query string
	var args []interface{}

	if isCandidate {
		// User is candidate -> Fetch company info
		query = `
			SELECT c.id, c.candidate_id, c.company_id, c.job_id, c.last_message, c.last_message_at,
			       comp.name as participant_name
			FROM conversations c
			JOIN companies comp ON c.company_id = comp.id
			WHERE c.candidate_id = $1
			ORDER BY c.last_message_at DESC NULLS LAST
		`
		args = append(args, userID)
	} else if tenantID != "" {
		// User is company admin -> Fetch candidate info
		query = `
			SELECT c.id, c.candidate_id, c.company_id, c.job_id, c.last_message, c.last_message_at,
			       COALESCE(u.name, u.full_name, u.identifier) as participant_name
			FROM conversations c
			JOIN users u ON c.candidate_id = u.id
			WHERE c.company_id = $1
			ORDER BY c.last_message_at DESC NULLS LAST
		`
		args = append(args, tenantID)
	} else {
		return nil, fmt.Errorf("invalid context for listing conversations")
	}

	rows, err := s.DB.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var convs []Conversation
	for rows.Next() {
		var c Conversation
		if err := rows.Scan(&c.ID, &c.CandidateID, &c.CompanyID, &c.JobID, &c.LastMessage, &c.LastMessageAt, &c.ParticipantName); err != nil {
			return nil, err
		}
		convs = append(convs, c)
	}
	return convs, nil
}
