package provider

import (
	"context"
	"fmt"
	"time"

	"terraform-provider-microsoftfabric/internal/apiclient"

	"github.com/hashicorp/terraform-plugin-framework/resource"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

// eventhouseResource defines the resource structure for managing Eventhouses.
type eventhouseResource struct {
	client *apiclient.APIClient // API client for making requests.
}

// Schema defines the schema for the Eventhouse resource.
func (r *eventhouseResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
	resp.Schema = schema.Schema{
		Attributes: map[string]schema.Attribute{
			"id": schema.StringAttribute{
				Computed: true, // ID is generated by the API upon creation.
			},
			"workspace_id": schema.StringAttribute{
				Required: true, // The unique identifier for the workspace.
			},
			"display_name": schema.StringAttribute{
				Required: true, // The name of the Eventhouse.
			},
			"description": schema.StringAttribute{
				Optional: true, // Optional description for the Eventhouse.
			},
			"last_updated": schema.StringAttribute{
				Computed: true, // Timestamp of the last update to the Eventhouse.
			},
		},
	}
}

// eventhouseResourceModel defines the model for managing the Eventhouse's state.
type eventhouseResourceModel struct {
	ID          types.String `tfsdk:"id"`           // Unique identifier for the Eventhouse
	WorkspaceID types.String `tfsdk:"workspace_id"` // ID of the workspace the Eventhouse belongs to
	DisplayName types.String `tfsdk:"display_name"` // Display name of the Eventhouse
	Description types.String `tfsdk:"description"`  // Description of the Eventhouse
	LastUpdated types.String `tfsdk:"last_updated"` // Timestamp of when the Eventhouse was last updated
}

// Metadata returns metadata about the Eventhouse resource.
func (r *eventhouseResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
	resp.TypeName = "microsoftfabric_eventhouse" // Name used in Terraform configuration
}

// NewEventhouseResource creates a new Eventhouse resource.
func NewEventhouseResource(client *apiclient.APIClient) resource.Resource {
	return &eventhouseResource{client: client} // Initialize with API client
}

// Create implements the creation of an Eventhouse resource.
func (r *eventhouseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
	// Retrieve the planned state of the resource
	var plan eventhouseResourceModel
	diags := req.Plan.Get(ctx, &plan)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}

	// Create the Eventhouse via the API client
	eventhouseID, err := r.createEventhouse(plan.WorkspaceID.ValueString(), plan.DisplayName.ValueString(), plan.Description.ValueString())
	if err != nil {
		// Add error diagnostics if creation fails
		resp.Diagnostics.AddError(
			"Error creating Eventhouse",
			"Could not create Eventhouse: "+err.Error(),
		)
		return
	}

	// Set the ID and LastUpdated fields
	plan.ID = types.StringValue(eventhouseID)                            // Set the ID returned from the API
	plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) // Current timestamp

	// Set the state of the resource in Terraform
	diags = resp.State.Set(ctx, plan)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}
}

// Read retrieves the current state of an Eventhouse resource.
func (r *eventhouseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
	// Retrieve the current state from the resource
	var state eventhouseResourceModel
	diags := req.State.Get(ctx, &state)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}

	// Read the Eventhouse details from the API
	eventhouse, err := r.readEventhouse(state.WorkspaceID.ValueString(), state.ID.ValueString())
	if err != nil {
		// Add error diagnostics if reading fails
		resp.Diagnostics.AddError(
			"Error reading Eventhouse",
			"Could not read Eventhouse: "+err.Error(),
		)
		return
	}

	// Update state with the values retrieved from the API
	state.DisplayName = types.StringValue(eventhouse.DisplayName.ValueString())
	state.Description = types.StringValue(eventhouse.Description.ValueString())
	state.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) // Update last modified timestamp

	diags = resp.State.Set(ctx, state)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}
}

// Update modifies an existing Eventhouse resource.
func (r *eventhouseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
	var plan eventhouseResourceModel
	diags := req.Plan.Get(ctx, &plan)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}

	var state eventhouseResourceModel
	diags = req.State.Get(ctx, &state)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}

	// Update the Eventhouse with new details
	err := r.updateEventhouse(state.WorkspaceID.ValueString(), state.ID.ValueString(), plan.DisplayName.ValueString(), plan.Description.ValueString())
	if err != nil {
		// Add error diagnostics if updating fails
		resp.Diagnostics.AddError(
			"Error updating Eventhouse",
			"Could not update Eventhouse: "+err.Error(),
		)
		return
	}

	// Set LastUpdated field to current timestamp
	plan.ID = state.ID // Ensure the ID remains unchanged
	plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))

	// Set the updated state
	diags = resp.State.Set(ctx, plan)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}
}

// Delete removes an Eventhouse resource.
func (r *eventhouseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
	var state eventhouseResourceModel
	diags := req.State.Get(ctx, &state)
	resp.Diagnostics.Append(diags...)
	if resp.Diagnostics.HasError() {
		return
	}

	// Remove the Eventhouse via the API
	err := r.deleteEventhouse(state.WorkspaceID.ValueString(), state.ID.ValueString())
	if err != nil {
		// Add error diagnostics if deletion fails
		resp.Diagnostics.AddError(
			"Error deleting Eventhouse",
			"Could not delete Eventhouse: "+err.Error(),
		)
		return
	}

	// Remove resource from state
	resp.State.RemoveResource(ctx)
}

// createEventhouse sends a request to create a new Eventhouse in the specified workspace.
func (r *eventhouseResource) createEventhouse(workspaceID, displayName, description string) (string, error) {
	// URL for the API endpoint to create an Eventhouse
	url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/eventhouses", workspaceID)
	body := map[string]interface{}{
		"displayName": displayName, // Set the display name
		"description": description, // Set the description
	}

	// Make a POST request to create the Eventhouse
	responseBody, err := r.client.Post(url, body) // Change from PostWithOperationCheck to Post
	if err != nil {
		return "", fmt.Errorf("failed to make POST request: %w", err) // Return the error on failure
	}

	// Extract the Eventhouse ID from the response
	eventhouseID, ok := responseBody["id"].(string) // Modify based on the actual response structure
	if !ok {
		return "", fmt.Errorf("unexpected response format: 'id' key not found") // Handle unexpected response
	}

	return eventhouseID, nil // Return the newly created Eventhouse ID
}

// readEventhouse retrieves the details of an existing Eventhouse.
func (r *eventhouseResource) readEventhouse(workspaceID, eventhouseID string) (eventhouseResourceModel, error) {
	// URL for the API endpoint to read an Eventhouse
	url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/eventhouses/%s", workspaceID, eventhouseID)

	responseBody, err := r.client.Get(url) // Fetch Eventhouse details from API
	if err != nil {
		return eventhouseResourceModel{}, err // Return error if fetching fails
	}

	// Map the response data to the Eventhouse model
	eventhouse := eventhouseResourceModel{
		ID:          types.StringValue(responseBody["id"].(string)),          // Eventhouse ID
		DisplayName: types.StringValue(responseBody["displayName"].(string)), // Eventhouse display name
		Description: types.StringValue(responseBody["description"].(string)), // Eventhouse description
	}

	return eventhouse, nil // Return the populated Eventhouse model
}

// updateEventhouse sends a request to update an existing Eventhouse.
func (r *eventhouseResource) updateEventhouse(workspaceID, eventhouseID, displayName, description string) error {
	// URL for the API endpoint to update an Eventhouse
	url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/eventhouses/%s", workspaceID, eventhouseID)
	body := map[string]interface{}{
		"displayName": displayName, // New display name for the Eventhouse
		"description": description, // New description for the Eventhouse
	}

	_, err := r.client.Patch(url, body) // Make PATCH request to update
	return err                          // Return any error encountered
}

// deleteEventhouse sends a request to delete an existing Eventhouse.
func (r *eventhouseResource) deleteEventhouse(workspaceID, eventhouseID string) error {
	// URL for the API endpoint to delete an Eventhouse
	url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/eventhouses/%s", workspaceID, eventhouseID)
	return r.client.Delete(url) // Make DELETE request and return any error
}
