package buckets

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"github.com/internxt/rclone-adapter/config"
	"github.com/internxt/rclone-adapter/errors"
)

type Shard struct {
	Hash string `json:"hash"`
	UUID string `json:"uuid"`
}

// CompletedPart represents a single uploaded part for multipart completion
type CompletedPart struct {
	PartNumber int    `json:"PartNumber"`
	ETag       string `json:"ETag"`
}

// MultipartShard represents a shard with multipart upload metadata
type MultipartShard struct {
	UUID     string          `json:"uuid"`
	Hash     string          `json:"hash"`
	UploadId string          `json:"UploadId"`
	Parts    []CompletedPart `json:"parts"`
}

type FinishUploadResp struct {
	Bucket   string `json:"bucket"`
	Index    string `json:"index"`
	ID       string `json:"id"`
	Version  int    `json:"version"`
	Created  string `json:"created"`
	Renewal  string `json:"renewal"`
	Mimetype string `json:"mimetype"`
	Filename string `json:"filename"`
}

func FinishUpload(ctx context.Context, cfg *config.Config, bucketID, index string, shards []Shard) (*FinishUploadResp, error) {
	url := cfg.Endpoints.Network().FinishUpload(bucketID)
	payload := map[string]interface{}{
		"index":  index,
		"shards": shards,
	}
	b, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal finish upload request: %w", err)
	}
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(b))
	if err != nil {
		return nil, fmt.Errorf("failed to create finish upload request: %w", err)
	}
	req.Header.Set("Authorization", cfg.BasicAuthHeader)
	req.Header.Set("internxt-version", "1.0")
	req.Header.Set("Content-Type", "application/json; charset=utf-8")

	resp, err := cfg.HTTPClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to execute finish upload request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.NewHTTPError(resp, "finish upload")
	}

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %w", err)
	}

	var result FinishUploadResp
	if err := json.Unmarshal(bodyBytes, &result); err != nil {
		return nil, fmt.Errorf("failed to unmarshal finish upload response: %w", err)
	}
	return &result, nil
}

// FinishMultipartUpload completes a multipart upload session
func FinishMultipartUpload(ctx context.Context, cfg *config.Config, bucketID, index string, shard MultipartShard) (*FinishUploadResp, error) {
	url := cfg.Endpoints.Network().FinishUpload(bucketID)
	payload := map[string]any{
		"index":  index,
		"shards": []MultipartShard{shard},
	}
	b, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal finish multipart upload request: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(b))
	if err != nil {
		return nil, fmt.Errorf("failed to create finish multipart upload request: %w", err)
	}
	req.Header.Set("Authorization", cfg.BasicAuthHeader)
	req.Header.Set("internxt-version", "1.0")
	req.Header.Set("Content-Type", "application/json; charset=utf-8")

	resp, err := cfg.HTTPClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to execute finish multipart upload request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.NewHTTPError(resp, "finish multipart upload")
	}

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %w", err)
	}

	var result FinishUploadResp
	if err := json.Unmarshal(bodyBytes, &result); err != nil {
		return nil, fmt.Errorf("failed to unmarshal finish multipart upload response: %w", err)
	}
	return &result, nil
}
