package parser

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"time"

	"github.com/openai/openai-go"
	"github.com/openai/openai-go/responses"

	"github.com/rjNemo/rentease/internal/service/booking"
)

type BookingAgentParser struct {
	systemPrompt string
	llmClient    openai.Client
}

func NewBookingAgentParser() *BookingAgentParser {
	return &BookingAgentParser{
		llmClient: openai.NewClient(),
		systemPrompt: `		Extract the following fields from the booking content and return a JSON object with this exact structure (all fields required, use null or empty string if not available):
		
		{
		  "data": {
			"arrival_date": "YYYY-MM-DD",
			"booking_fees": "number as string",
			"booking_id": "string",
			"departure_date": "YYYY-MM-DD",
			"stay_length": int,
			"guest_email": "string",
			"guest_name": "string",
			"guest_number": int,
			"guest_phone": "string",
			"room_booked": "string",
			"standard_rate": "number as string",
			"special_requests": "string"
		  }
		}
		
		Respond ONLY with the JSON object above, wrapped in a top-level "data" field as shown, no code fences.
		
		Booking content:`,
	}
}

// ResponseData is the expected structure returned by the LLM parser.
type ResponseData struct {
	ArrivalDate     string      `json:"arrival_date"`
	BookingFees     json.Number `json:"booking_fees"`
	BookingID       string      `json:"booking_id"`
	DepartureDate   string      `json:"departure_date"`
	StayLength      int         `json:"stay_length"`
	GuestEmail      string      `json:"guest_email"`
	GuestName       string      `json:"guest_name"`
	GuestNumber     int         `json:"guest_number"`
	GuestPhone      string      `json:"guest_phone"`
	RoomBooked      string      `json:"room_booked"`
	StandardRate    json.Number `json:"standard_rate"`
	SpecialRequests string      `json:"special_requests"`
}

func (p *BookingAgentParser) Parse(rawContent string) (*booking.Booking, error) {
	log.Println("sending request to OpenAI LLM parser")

	ctx := context.Background()

	prompt := p.systemPrompt + "\n" + rawContent

	resp, err := p.llmClient.Responses.New(ctx, responses.ResponseNewParams{
		Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(prompt)},
		Model: openai.ChatModelChatgpt4oLatest,
	})
	if err != nil {
		return nil, fmt.Errorf("error sending request to OpenAI: %w", err)
	}

	var r struct {
		Data ResponseData `json:"data"`
	}

	// The LLM is instructed to return the JSON for ResponseData directly, so parse it
	err = json.Unmarshal([]byte(resp.OutputText()), &r)
	if err != nil {
		return nil, fmt.Errorf("error decoding response from OpenAI: %w", err)
	}

	var b booking.Booking
	b.From, err = time.Parse("2006-01-02", r.Data.ArrivalDate)
	if err != nil {
		return nil, fmt.Errorf("error parsing arrival_date: %w", err)
	}
	b.To, err = time.Parse("2006-01-02", r.Data.DepartureDate)
	if err != nil {
		return nil, fmt.Errorf("error parsing departure_date: %w", err)
	}
	b.Name = r.Data.GuestName
	b.PhoneNumber = r.Data.GuestPhone
	b.Email = r.Data.GuestEmail
	b.CustomerNumber = r.Data.GuestNumber
	bookingFees, err := r.Data.BookingFees.Float64()
	if err != nil {
		return nil, fmt.Errorf("error parsing booking fees: %w", err)
	}
	b.Platform = "Booking"
	b.PlatformFees = bookingFees
	b.ExternalId = &r.Data.BookingID

	price, err := r.Data.StandardRate.Float64()
	if err != nil {
		return nil, fmt.Errorf("error parsing standard rate: %w", err)
	}
	b.Items = append(b.Items, booking.Item{
		Item:          r.Data.RoomBooked,
		Quantity:      r.Data.StayLength,
		Price:         price,
		PaymentMethod: "Card",
	})

	return &b, nil
}
