package provider

import (
    "context"
    "encoding/json"
    "fmt"
    "terraform-provider-microsoftfabric/internal/apiclient"
    "time"

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

// Define the shortcut resource.
type shortcutResource struct {
    client *apiclient.APIClient
}
// Define the schema for the shortcut resource.
func (r *shortcutResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "id": schema.StringAttribute{
                Computed: true,
                Description: "The unique identifier for the shortcut, generated by the system.",
            },
            "workspace_id": schema.StringAttribute{
                Required: true,
                Description: "The ID of the workspace where the shortcut belongs.",
            },
            "item_id": schema.StringAttribute{
                Required: true,
                Description: "The ID of the item associated with the shortcut.",
            },
            "path": schema.StringAttribute{
                Required: true,
                Description: "The path within the workspace to the shortcut.",
            },
            "name": schema.StringAttribute{
                Required: true,
                Description: "The name of the shortcut.",
            },
            "target": schema.SingleNestedAttribute{
                Required: true,
                Description: "The target storage location where the shortcut points.",
                Attributes: map[string]schema.Attribute{
                    "adls_gen2": schema.SingleNestedAttribute{
                        Optional: true,
                        Description: "Configuration details for an Azure Data Lake Storage Gen2 target.",
                        Attributes: map[string]schema.Attribute{
                            "location": schema.StringAttribute{
                                Required:    true,
                                Description: "The URL of the Azure Data Lake Storage location.",
                            },
                            "subpath": schema.StringAttribute{
                                Required:    true,
                                Description: "The subpath within the Azure Data Lake Storage to the resource.",
                            },
                            "connection_id": schema.StringAttribute{
                                Required:    true,
                                Description: "Gateway Connection ID",
                            },
                        },
                    },
                    "amazon_s3": schema.SingleNestedAttribute{
                        Optional: true,
                        Description: "Configuration details for an Amazon S3 target.",
                        Attributes: map[string]schema.Attribute{
                            "location": schema.StringAttribute{
                                Required:    true,
                                Description: "The URL of the Amazon S3 bucket.",
                            },
                            "subpath": schema.StringAttribute{
                                Required:    true,
                                Description: "The subpath within the Amazon S3 bucket to the resource.",
                            },
                            "connection_id": schema.StringAttribute{
                                Required:    true,
                                Description: "Gateway Connection ID",
                            },
                        },
                    },
                    "google_cloud_storage": schema.SingleNestedAttribute{
                        Optional: true,
                        Description: "Configuration details for a Google Cloud Storage target.",
                        Attributes: map[string]schema.Attribute{
                            "location": schema.StringAttribute{
                                Required:    true,
                                Description: "The URL of the Google Cloud Storage bucket.",
                            },
                            "subpath": schema.StringAttribute{
                                Required:    true,
                                Description: "The subpath within the Google Cloud Storage bucket to the resource.",
                            },
                            "connection_id": schema.StringAttribute{
                                Required:    true,
                                Description: "Gateway Connection ID",
                            },
                        },
                    },
                },
            },
            "last_updated": schema.StringAttribute{
                Computed: true,
                Description: "The timestamp of the last update made to the shortcut.",
            },
        },
    }
}

// Define the model for the shortcut resource.
type shortcutResourceModel struct {
    ID          types.String   `tfsdk:"id"`
    WorkspaceID types.String   `tfsdk:"workspace_id"`
    ItemID      types.String   `tfsdk:"item_id"`
    Path        types.String   `tfsdk:"path"`
    Name        types.String   `tfsdk:"name"`
    Target      TargetModel    `tfsdk:"target"`
    LastUpdated types.String   `tfsdk:"last_updated"`
}

// Define a unified target model for multiple cloud storage options.
type TargetModel struct {
    ADLSGen2          *ADLSGen2TargetModel  `tfsdk:"adls_gen2"`
    AmazonS3          *AmazonS3TargetModel  `tfsdk:"amazon_s3"`
    GoogleCloudStorage *GCSModel             `tfsdk:"google_cloud_storage"`
}

// Define models for ADLS Gen2, Amazon S3, and Google Cloud Storage targets.
type ADLSGen2TargetModel struct {
    Location     types.String `tfsdk:"location"`
    Subpath      types.String `tfsdk:"subpath"`
    ConnectionID types.String `tfsdk:"connection_id"`
}

type AmazonS3TargetModel struct {
    Location     types.String `tfsdk:"location"`
    Subpath      types.String `tfsdk:"subpath"`
    ConnectionID types.String `tfsdk:"connection_id"`
}

type GCSModel struct {
    Location     types.String `tfsdk:"location"`
    Subpath      types.String `tfsdk:"subpath"`
    ConnectionID types.String `tfsdk:"connection_id"`
}

// Implement Metadata method.
func (r *shortcutResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
    resp.TypeName = "microsoftfabric_shortcut"
}

// Define the provider.
func NewShortcutResource(client *apiclient.APIClient) resource.Resource {
    return &shortcutResource{client: client}
}

// Implement CRUD operations.
func (r *shortcutResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    // Retrieve values from plan.
    var plan shortcutResourceModel
    diags := req.Plan.Get(ctx, &plan)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Create the shortcut.
    err := r.createShortcut(plan.WorkspaceID.ValueString(), plan.ItemID.ValueString(), plan.Path.ValueString(), plan.Name.ValueString(), plan.Target)
    if err != nil {
        resp.Diagnostics.AddError(
            "Error creating shortcut",
            "Could not create shortcut: "+err.Error(),
        )
        return
    }

    // Set the ID as "path/name".
    plan.ID = types.StringValue(plan.Path.ValueString() + "/" + plan.Name.ValueString())
    plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) // Set LastUpdated to the current time

    // Set state.
    diags = resp.State.Set(ctx, plan)
    resp.Diagnostics.Append(diags...)
}

func (r *shortcutResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
    // Retrieve ID from state.
    var state shortcutResourceModel
    diags := req.State.Get(ctx, &state)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Implement the logic to read the current state if necessary.
}

// The Update function that first deletes the existing shortcut and then creates a new one.
func (r *shortcutResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
    // Retrieve the currently stored state.
    var state shortcutResourceModel
    diags := req.State.Get(ctx, &state)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Delete the existing shortcut.
    err := r.deleteShortcut(state.WorkspaceID.ValueString(), state.ItemID.ValueString(), state.Path.ValueString(), state.Name.ValueString())
    if err != nil {
        resp.Diagnostics.AddError(
            "Error deleting shortcut",
            fmt.Sprintf("Could not delete existing shortcut: %s", err.Error()),
        )
        return
    }

    // Prepare new values for the shortcut from the request.
    var plan shortcutResourceModel
    diags = req.Plan.Get(ctx, &plan)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Create the updated shortcut using the new values from the plan.
    err = r.createShortcut(plan.WorkspaceID.ValueString(), plan.ItemID.ValueString(), plan.Path.ValueString(), plan.Name.ValueString(), plan.Target)
    if err != nil {
        resp.Diagnostics.AddError(
            "Error creating shortcut",
            fmt.Sprintf("Could not create updated shortcut: %s", err.Error()),
        )
        return
    }

    // Update the state to reflect the change.
    state.Path = plan.Path // Update any specific fields as necessary
    state.Name = plan.Name // Update the name, etc.

    // Save the updated state.
    diags = resp.State.Set(ctx, &state)
    resp.Diagnostics.Append(diags...)
}

func (r *shortcutResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
    // Retrieve state from the request.
    var state shortcutResourceModel
    diags := req.State.Get(ctx, &state)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Delete the shortcut using the helper function.
    err := r.deleteShortcut(state.WorkspaceID.ValueString(), state.ItemID.ValueString(), state.Path.ValueString(), state.Name.ValueString())
    if err != nil {
        resp.Diagnostics.AddError(
            "Error deleting shortcut",
            fmt.Sprintf("Could not delete shortcut: %s", err.Error()),
        )
        return
    }

    // Optionally set state to nil or remove the resource from the state.
    resp.State.RemoveResource(ctx)
}

// Helper function to create a shortcut.
func (r *shortcutResource) createShortcut(workspaceID, itemID, path, name string, target TargetModel) error {
    url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/items/%s/shortcuts", workspaceID, itemID)

    // Prepare the request body based on the target type
    var targetConfig map[string]interface{}
    if target.ADLSGen2 != nil {
        targetConfig = map[string]interface{}{
            "adlsGen2": map[string]interface{}{
                "location":     target.ADLSGen2.Location.ValueString(),
                "subpath":      target.ADLSGen2.Subpath.ValueString(),
                "connectionId": target.ADLSGen2.ConnectionID.ValueString(),
            },
        }
    } else if target.AmazonS3 != nil {
        targetConfig = map[string]interface{}{
            "amazonS3": map[string]interface{}{
                "location":     target.AmazonS3.Location.ValueString(),
                "subpath":      target.AmazonS3.Subpath.ValueString(),
                "connectionId": target.AmazonS3.ConnectionID.ValueString(),
            },
        }
    } else if target.GoogleCloudStorage != nil {
        targetConfig = map[string]interface{}{
            "googleCloudStorage": map[string]interface{}{
                "location":     target.GoogleCloudStorage.Location.ValueString(),
                "subpath":      target.GoogleCloudStorage.Subpath.ValueString(),
                "connectionId": target.GoogleCloudStorage.ConnectionID.ValueString(),
            },
        }
    } else {
        return fmt.Errorf("no valid target specified")
    }

    // Prepare the complete body
    body := map[string]interface{}{
        "path":   path,
        "name":   name,
        "target": targetConfig,
    }

    bodyBytes, err := json.Marshal(body)
    if err != nil {
        return fmt.Errorf("failed to marshal request body: %v", err)
    }

    resp, err := r.client.PostBytes(url, bodyBytes)
    if err != nil {
        return fmt.Errorf("failed to create shortcut: %v", err)
    }

    // Log the API response for debugging or confirmation.
    fmt.Printf("API Response: %+v\n", resp)

    return nil
}

func (r *shortcutResource) deleteShortcut(workspaceID, itemID, path, name string) error {
    url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/items/%s/shortcuts/%s/%s",
        workspaceID, itemID, path, name)

    // Perform the DELETE request.
    err := r.client.Delete(url) // Assuming Delete only returns error
    if err != nil {
        return fmt.Errorf("failed to delete shortcut: %v", err)
    }

    return nil
}