package gemini

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

	"github.com/jobs-scraper/internal/pkg/domain"
	"google.golang.org/genai"
)

type GeminiService struct {
	client *genai.Client
	model  string
}

func NewGeminiService(ctx context.Context, key, model string) (*GeminiService, error) {
	config := genai.ClientConfig{
		APIKey: key,
	}
	client, err := genai.NewClient(ctx, &config)

	if err != nil {
		return nil, err
	}

	return &GeminiService{client: client, model: model}, nil
}

func (gs *GeminiService) ParseJobData(ctx context.Context, htmlContent string) (*domain.JobDescription, error) {
	prompt := fmt.Sprintf(`Extract job posting information from the following HTML content.

CRITICAL RULES:
1. Return ONLY valid JSON - no markdown, no code blocks, no backticks, no explanations
2. Use SINGLE-LINE JSON (no pretty printing, no newlines inside the JSON)
3. All criteria values MUST be strings (never use booleans, numbers, or arrays)
4. Properly escape all quotes inside strings using \"
5. Use only standard ASCII quotes ("), never smart quotes (" " ' ')

Required fields:
- description: Full job description as a single string
- criteria: Object with keys like title, company, location, salary, skills, experience, job_type, remote

Example (SINGLE LINE):
{"description":"Full job description text here...","criteria":{"title":"Software Engineer","location":"City, Country","salary":"$100k-$150k","skills":"Go, Python, Docker","experience":"3-5 years","job_type":"Full-time","remote":"Remote"}}

HTML Content:
%s`, htmlContent)
	response, err := gs.client.Models.GenerateContent(
		ctx,
		gs.model,
		genai.Text(prompt),
		nil,
	)
	if err != nil {
		return &domain.JobDescription{}, err
	}

	jsonContent := response.Text()

	log.Printf("Raw API response for job description: %s", jsonContent)

	jsonContent = cleanMarkdownCodeBlocks(jsonContent)

	log.Printf("Cleaned JSON (first 500 chars): %s", jsonContent[:min(500, len(jsonContent))])

	var result struct {
		Description string            `json:"description"`
		Criteria    map[string]string `json:"criteria"`
	}

	if err := json.Unmarshal([]byte(jsonContent), &result); err != nil {
		if syntaxErr, ok := err.(*json.SyntaxError); ok {
			start := int(syntaxErr.Offset) - 50
			if start < 0 {
				start = 0
			}
			end := int(syntaxErr.Offset) + 50
			if end > len(jsonContent) {
				end = len(jsonContent)
			}
			log.Printf("JSON parse error at position %d, context: ...%s...", syntaxErr.Offset, jsonContent[start:end])
		}

		return nil, fmt.Errorf("failed to parse JSON response: %v. Cleaned JSON length: %d", err, len(jsonContent))
	}

	jobDescription := &domain.JobDescription{
		Description: result.Description,
		Criteria:    result.Criteria,
	}

	return jobDescription, nil
}

// cleanMarkdownCodeBlocks removes markdown code block formatting from JSON response
func cleanMarkdownCodeBlocks(content string) string {
	// Remove ```json prefix and ``` suffix if present
	content = strings.TrimSpace(content)

	// Remove opening code block markers
	if strings.HasPrefix(content, "```json") {
		content = strings.TrimPrefix(content, "```json")
	} else if strings.HasPrefix(content, "```") {
		content = strings.TrimPrefix(content, "```")
	}

	// Remove closing code block markers
	content = strings.TrimSuffix(content, "```")

	return strings.TrimSpace(content)
}
