package main

import (
	"backend/config"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"os"
	"path/filepath"
	"time"
)

func HealthCheckStorage() error {
	resp, err := http.Get(config.Cfg.Storage.Endpoint + "/health")
	if err != nil {
		return fmt.Errorf("storage health check failed: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("storage health check failed: %s", resp.Status)
	}
	return nil
}

func DeleteFile(id string) error {
	req, err := http.NewRequest("DELETE", config.Cfg.Storage.Endpoint+"/delete/"+id+"?token="+config.Cfg.Storage.Token, nil)
	if err != nil {
		return fmt.Errorf("failed to create delete request: %w", err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("delete request failed: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("delete failed: %s", resp.Status)
	}
	return nil
}

func DeleteIdsFromStorage(ids []string) error {
	for _, id := range ids {
		err := DeleteFile(id)
		if err != nil {
			return fmt.Errorf("failed to delete file with id %s: %w", id, err)
		}
	}
	return nil
}

func GetFile(path string) ([]byte, error) {
	panic("unimplemented")
}

type FileMetadata struct {
	ID           string     `json:"id"`
	OriginalName string     `json:"originalName"`
	Size         int64      `json:"size"`
	MIMEType     string     `json:"mimeType"`
	BlockCount   int        `json:"blockCount"`
	UploadedAt   time.Time  `json:"uploadedAt"`
	ExpiresAt    *time.Time `json:"expiresAt"`
	Bucket       string     `json:"bucket,omitempty"`
}

// func ListFiles() ([]FileMetadata, error) {
// 	//get list of files from api
// 	resp, err := http.Get(config.Cfg.Storage.Endpoint + "/files?token=" + config.Cfg.Storage.Token)
// 	if err != nil {
// 		return nil, err
// 	}
// 	defer resp.Body.Close()

// 	if resp.StatusCode != http.StatusOK {
// 		return nil, fmt.Errorf("failed to list files: %s", resp.Status)
// 	}
// 	//parse response
// 	body, err := io.ReadAll(resp.Body)
// 	if err != nil {
// 		fmt.Println("Error reading response body:", err)
// 		return nil, err
// 	}
// 	var data []FileMetadata
// 	err = json.Unmarshal(body, &data)
// 	if err != nil {
// 		fmt.Println("Error unmarshalling response body:", err)
// 		return nil, err
// 	}

// 	return data, nil

// }

func ListBucket(bucketName string) ([]FileMetadata, error) {
	//get list of files from api
	resp, err := http.Get(config.Cfg.Storage.Endpoint + "/bucket/" + bucketName + "?token=" + config.Cfg.Storage.Token)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to list files: %s", resp.Status)
	}
	//parse response
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return nil, err
	}
	var data []FileMetadata
	err = json.Unmarshal(body, &data)
	if err != nil {
		fmt.Println("Error unmarshalling response body:", err)
		return nil, err
	}
	return data, nil
}

// type CheckFileResponse struct {
// 	Available   []FileMetadata `json:"available"`
// 	Unavailable []string       `json:"unavailable"`
// }

// func CheckFiles(ids []string) ([]FileMetadata, []string, error) {

// 	//application/json with array of ids as body of post request to /files-check
// 	jsonData, err := json.Marshal(ids)
// 	if err != nil {
// 		return nil, nil, err
// 	}
// 	resp, err := http.Post(config.Cfg.Storage.Endpoint+"/files-check?token="+config.Cfg.Storage.Token,
// 		"application/json", bytes.NewBuffer(jsonData))
// 	if err != nil {
// 		return nil, nil, err
// 	}
// 	defer resp.Body.Close()

// 	if resp.StatusCode != http.StatusOK {
// 		return nil, nil, fmt.Errorf("failed to check files: %s", resp.Status)
// 	}
// 	//parse response
// 	body, err := io.ReadAll(resp.Body)
// 	if err != nil {
// 		fmt.Println("Error reading response body:", err)
// 		return nil, nil, err
// 	}
// 	var data CheckFileResponse
// 	err = json.Unmarshal(body, &data)
// 	if err != nil {
// 		fmt.Println("Error unmarshalling response body:", err)
// 		return nil, nil, err
// 	}
// 	return data.Available, data.Unavailable, nil

// }

func UploadFile(path string, mimeType string, bucket string) (string, error) {

	file, err := os.Open(path)
	if err != nil {
		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer file.Close()

	var body bytes.Buffer
	writer := multipart.NewWriter(&body)

	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, filepath.Base(path)))
	h.Set("Content-Type", mimeType)
	part, err := writer.CreatePart(h)
	if err != nil {
		return "", fmt.Errorf("failed to create form file: %w", err)
	}
	if _, err := io.Copy(part, file); err != nil {
		return "", fmt.Errorf("failed to copy file data: %w", err)
	}

	err = writer.WriteField("bucket", bucket)
	if err != nil {
		return "", fmt.Errorf("failed to write bucket field: %w", err)
	}

	if err := writer.Close(); err != nil {
		return "", fmt.Errorf("failed to close writer: %w", err)
	}

	req, err := http.NewRequest("POST", config.Cfg.Storage.Endpoint+"/upload?token="+config.Cfg.Storage.Token, &body)
	if err != nil {
		return "", fmt.Errorf("failed to create upload request: %w", err)
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

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

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("upload failed: %s", resp.Status)
	}
	//parse response
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read upload response: %w", err)
	}
	var data map[string]string
	err = json.Unmarshal(respBody, &data)
	if err != nil {
		return "", fmt.Errorf("failed to parse upload response: %w", err)
	}
	if id, ok := data["id"]; ok {
		return id, nil
	}

	return "", nil

}
