// Path: Code/Tracker/clients/tools.go

package clients

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type ToolsClient struct {
	baseURL    string
	httpClient *http.Client
}

type ExcelReadResponse struct {
	FilePath  string                   `json:"file_path"`
	SheetName string                   `json:"sheet_name"`
	HeaderRow int                      `json:"header_row"`
	Columns   []string                 `json:"columns"`
	RowCount  int                      `json:"row_count"`
	Rows      []map[string]interface{} `json:"rows"`
}

type ExcelFindResponse struct {
	Found   bool                   `json:"found"`
	RowNum  int                    `json:"row_num"`
	Row     map[string]interface{} `json:"row"`
	Message string                 `json:"message"`
}

type ExcelWriteRequest struct {
	FilePath  string                 `json:"file_path"`
	SheetName string                 `json:"sheet_name"`
	HeaderRow int                    `json:"header_row"`
	Row       map[string]interface{} `json:"row"`
}

type ExcelUpdateRequest struct {
	FilePath  string                 `json:"file_path"`
	SheetName string                 `json:"sheet_name"`
	HeaderRow int                    `json:"header_row"`
	RowNum    int                    `json:"row_num"`
	Row       map[string]interface{} `json:"row"`
}

func NewToolsClient(baseURL string) *ToolsClient {
	return &ToolsClient{
		baseURL: strings.TrimSuffix(baseURL, "/"),
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

func (c *ToolsClient) Health() error {
	resp, err := c.httpClient.Get(c.baseURL + "/health")
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("tools unhealthy: status %d", resp.StatusCode)
	}
	return nil
}

func (c *ToolsClient) ReadExcel(filePath, sheetName string, headerRow int) (*ExcelReadResponse, error) {
	params := url.Values{}
	params.Set("file_path", filePath)
	params.Set("sheet_name", sheetName)
	params.Set("header_row", strconv.Itoa(headerRow))

	resp, err := c.httpClient.Get(c.baseURL + "/excel/read?" + params.Encode())
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("tools error: status %d, body: %s", resp.StatusCode, string(body))
	}

	var result ExcelReadResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	return &result, nil
}

func (c *ToolsClient) FindRow(filePath, sheetName string, headerRow int, column, value string) (*ExcelFindResponse, error) {
	params := url.Values{}
	params.Set("file_path", filePath)
	params.Set("sheet_name", sheetName)
	params.Set("header_row", strconv.Itoa(headerRow))
	params.Set("column", column)
	params.Set("value", value)

	resp, err := c.httpClient.Get(c.baseURL + "/excel/find?" + params.Encode())
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotFound {
		return &ExcelFindResponse{Found: false}, nil
	}

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("tools error: status %d, body: %s", resp.StatusCode, string(body))
	}

	var result ExcelFindResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	return &result, nil
}

func (c *ToolsClient) AddRow(filePath, sheetName string, headerRow int, row map[string]interface{}) error {
	reqBody := ExcelWriteRequest{
		FilePath:  filePath,
		SheetName: sheetName,
		HeaderRow: headerRow,
		Row:       row,
	}

	jsonBody, err := json.Marshal(reqBody)
	if err != nil {
		return fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := c.httpClient.Post(c.baseURL+"/excel/row", "application/json", bytes.NewReader(jsonBody))
	if err != nil {
		return fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("tools error: status %d, body: %s", resp.StatusCode, string(body))
	}

	return nil
}

func (c *ToolsClient) UpdateRow(filePath, sheetName string, headerRow, rowNum int, row map[string]interface{}) error {
	reqBody := ExcelUpdateRequest{
		FilePath:  filePath,
		SheetName: sheetName,
		HeaderRow: headerRow,
		RowNum:    rowNum,
		Row:       row,
	}

	jsonBody, err := json.Marshal(reqBody)
	if err != nil {
		return fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequest("PUT", c.baseURL+"/excel/row/"+strconv.Itoa(rowNum), bytes.NewReader(jsonBody))
	if err != nil {
		return fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("tools error: status %d, body: %s", resp.StatusCode, string(body))
	}

	return nil
}

func (c *ToolsClient) CreateTracker(filePath, sheetName string, columns []string) error {
	reqBody := map[string]interface{}{
		"file_path":  filePath,
		"sheet_name": sheetName,
		"columns":    columns,
	}

	jsonBody, err := json.Marshal(reqBody)
	if err != nil {
		return fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := c.httpClient.Post(c.baseURL+"/excel/create", "application/json", bytes.NewReader(jsonBody))
	if err != nil {
		return fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("tools error: status %d, body: %s", resp.StatusCode, string(body))
	}

	return nil
}
