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"
)

type lakehouseTableResource struct {
    client *apiclient.APIClient
}

func (r *lakehouseTableResource) 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 lakehouse table, generated by the system.",
            },
            "workspace_id": schema.StringAttribute{
                Required: true,
                Description: "The ID of the workspace to which the lakehouse table belongs.",
            },
            "lakehouse_id": schema.StringAttribute{
                Required: true,
                Description: "The ID of the lakehouse to which the table belongs.",
            },
            "table_name": schema.StringAttribute{
                Required: true,
                Description: "The name of the lakehouse table.",
            },
            "relative_path": schema.StringAttribute{
                Required: true,
                Description: "The relative path to the table in the filesystem.",
            },
            "path_type": schema.StringAttribute{
                Required: true,
                Description: "The type of path used (absolute or relative).",
            },
            "mode": schema.StringAttribute{
                Required: true,
                Description: "The mode of the table operation (e.g., overwrite, append).",
            },
            "recursive": schema.BoolAttribute{
                Optional: true,
                Description: "Whether to load data recursively.",
            },
            "file_extension": schema.StringAttribute{
                Optional: true,
                Description: "The file extension to look for.",
            },
            "format_options": schema.SingleNestedAttribute{
                Required: true,
                Attributes: map[string]schema.Attribute{
                    "format": schema.StringAttribute{
                        Required: true,
                        Description: "The format of the data (e.g., csv, parquet).",
                    },
                    "header": schema.BoolAttribute{
                        Optional: true,
                        Description: "Whether the data includes a header row.",
                    },
                    "delimiter": schema.StringAttribute{
                        Optional: true,
                        Description: "The delimiter used in the data format.",
                    },
                },
            },
            "last_updated": schema.StringAttribute{
                Computed: true,
                Description: "The timestamp of the last update made to the table.",
            },
        },
    }
}

type lakehouseTableResourceModel struct {
    ID            types.String       `tfsdk:"id"`
    WorkspaceID   types.String       `tfsdk:"workspace_id"`
    LakehouseID   types.String       `tfsdk:"lakehouse_id"`
    TableName     types.String       `tfsdk:"table_name"`
    RelativePath  types.String       `tfsdk:"relative_path"`
    PathType      types.String       `tfsdk:"path_type"`
    Mode          types.String       `tfsdk:"mode"`
    Recursive     types.Bool         `tfsdk:"recursive"`
    FileExtension types.String       `tfsdk:"file_extension"`
    FormatOptions formatOptionsModel `tfsdk:"format_options"`
    LastUpdated   types.String       `tfsdk:"last_updated"`
}

type formatOptionsModel struct {
    Format    types.String `tfsdk:"format"`
    Header    types.Bool   `tfsdk:"header"`
    Delimiter types.String `tfsdk:"delimiter"`
}

func (r *lakehouseTableResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
    resp.TypeName = "microsoftfabric_lakehouse_table"
}

func NewLakehouseTableResource(client *apiclient.APIClient) resource.Resource {
    return &lakehouseTableResource{client: client}
}

func (r *lakehouseTableResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    var plan lakehouseTableResourceModel
    diags := req.Plan.Get(ctx, &plan)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    operationID, err := r.loadTable(plan)
    if err != nil {
        resp.Diagnostics.AddError(
            "Error loading table",
            "Could not load table: "+err.Error(),
        )
        return
    }

    plan.ID = types.StringValue(operationID)
    plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))

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

func (r *lakehouseTableResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
    var state lakehouseTableResourceModel
    diags := req.State.Get(ctx, &state)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Construct the URL to get table details
    url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/lakehouses/%s/tables",
        state.WorkspaceID.ValueString(), state.LakehouseID.ValueString())

    // Call the API to get table data
    tableInfo, err := r.client.Get(url)
    if err != nil {
        resp.Diagnostics.AddError(
            "Error reading tables",
            fmt.Sprintf("Could not read table data: %s", err),
        )
        return
    }

    tables := tableInfo // Use it directly as it is of type map[string]interface{}

    // Extract relevant data from the response
    data, exists := tables["data"].([]interface{})
    if !exists {
        resp.Diagnostics.AddError("Error reading tables", "No 'data' field found in response.")
        return
    }

    currentTableNames := make(map[string]struct{})
    for _, item := range data {
        if itemMap, valid := item.(map[string]interface{}); valid {
            if name, exists := itemMap["name"].(string); exists {
                currentTableNames[name] = struct{}{}
            }
        }
    }

    // Check if the table name in the state exists in the current tables
    if state.TableName.ValueString() != "" {
        if _, exists := currentTableNames[state.TableName.ValueString()]; !exists {
            resp.Diagnostics.AddWarning(
                "Table missing",
                fmt.Sprintf("The table '%s' specified in the state does not exist in the lakehouse. Terraform will recreate it.", state.TableName.ValueString()),
            )
            // Remove the resource from state to force a recreation
            resp.State.RemoveResource(ctx)
            return
        }
    }

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


func (r *lakehouseTableResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
    resp.Diagnostics.AddError("Error updating resource", "Update operation for lakehouse table is not supported.")
}

func (r *lakehouseTableResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
    var state lakehouseTableResourceModel
    diags := req.State.Get(ctx, &state)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    // Deletion logic might be added here, if needed
    resp.State.RemoveResource(ctx)

}
func (r *lakehouseTableResource) loadTable(plan lakehouseTableResourceModel) (string, error) {
    url := fmt.Sprintf("https://api.fabric.microsoft.com/v1/workspaces/%s/lakehouses/%s/tables/%s/load",
        plan.WorkspaceID.ValueString(), plan.LakehouseID.ValueString(), plan.TableName.ValueString())

    body := map[string]interface{}{
        "relativePath":  plan.RelativePath.ValueString(),
        "pathType":      plan.PathType.ValueString(),
        "mode":          plan.Mode.ValueString(),
        "recursive":     plan.Recursive.ValueBool(),
        "fileExtension": plan.FileExtension.ValueString(),
        "format":        plan.FormatOptions.Format.ValueString(),
        "header":        plan.FormatOptions.Header.ValueBool(),
        "delimiter":     plan.FormatOptions.Delimiter.ValueString(),
    }

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

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

    id := fmt.Sprintf("Files/%s", plan.TableName.ValueString())

    return id, nil
}
