package com.kbs.kbsintranett;

import android.Manifest;
import android.animation.LayoutTransition;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.OpenableColumns;
import android.text.Editable;
import android.text.Html;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

public class FormsFragment extends Fragment {

    private static final String TAG = "FormsFragment";
    private static final String BASE_URL_GF = "https://intranet.kbs.no/wp-json/gf/v2";

    // SKJEMA ID-er
    private static final int ID_ANSATTEOPPLYSNINGER = 1;
    private static final int ID_RUH = 4;
    private static final int ID_SIKKERHETSKURS = 9;
    private static final int ID_HMS_BEKREFTELSE = 10;
    private static final int ID_EGENMELDING = 11;
    private static final int ID_SJA = 14;
    private static final int ID_FRAVARSVARSEL = 15;
    private static final int ID_REFUSJON_UTLEGG = 16;

    private int formId = 1;

    private LinearLayout formContainer;
    private LinearLayout historyContainer;
    private View historyWrapper;
    private TextView txtStatus;
    private TextView lblHistory;
    private ProgressBar loadingSpinner;
    private ImageView btnToggleHistory;
    private Toolbar toolbar; // NYTT

    // --- HOVEDSKJEMA STATE ---
    private Map<String, View> fieldWrappers = new HashMap<>();
    private Map<String, View> inputViews = new HashMap<>();
    private Map<String, Boolean> requiredFieldsMap = new HashMap<>();
    private Map<String, Uri> fileUploads = new HashMap<>();

    // --- NESTED FORM (BARN) STATE ---
    private Map<String, View> childInputViews = new HashMap<>();
    private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>();
    private Map<String, Uri> childFileUploads = new HashMap<>();

    private List<NestedEntry> nestedEntries = new ArrayList<>();
    private LinearLayout nestedEntriesContainer;
    private TextView totalAmountView;

    // --- FILOPPLASTING & KAMERA ---
    private String pendingFileFieldId = null;
    private boolean isSelectingForChild = false;
    private Uri currentPhotoUri = null;

    private ActivityResultLauncher<Intent> filePickerLauncher;
    private ActivityResultLauncher<Uri> takePictureLauncher;
    private ActivityResultLauncher<String> requestPermissionLauncher;

    private GravityForm currentForm;
    private final OkHttpClient client = new OkHttpClient();

    private static final Pattern TITLE_PATTERN = Pattern.compile("^(\\d+)[.\\s-]+\\s*(.*)");

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        filePickerLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
                        Uri uri = result.getData().getData();
                        if (uri != null && pendingFileFieldId != null) {
                            handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
                        }
                    }
                }
        );
        takePictureLauncher = registerForActivityResult(
                new ActivityResultContracts.TakePicture(),
                success -> {
                    if (success && currentPhotoUri != null && pendingFileFieldId != null) {
                        handleFileSelection(pendingFileFieldId, currentPhotoUri, isSelectingForChild);
                    } else if (!success) {
                        currentPhotoUri = null;
                    }
                }
        );
        requestPermissionLauncher = registerForActivityResult(
                new ActivityResultContracts.RequestPermission(),
                isGranted -> {
                    if (isGranted) {
                        openCamera();
                    } else {
                        Toast.makeText(getContext(), "Kameratillatelse er påkrevd for å ta bilde.", Toast.LENGTH_LONG).show();
                    }
                }
        );
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_forms, container, false);
        formContainer = view.findViewById(R.id.form_container);
        historyContainer = view.findViewById(R.id.historyContainer);
        historyWrapper = view.findViewById(R.id.history_wrapper);
        txtStatus = view.findViewById(R.id.txt_status);
        lblHistory = view.findViewById(R.id.lbl_history);
        loadingSpinner = view.findViewById(R.id.loading_spinner);

        // NYTT: Finn toolbar og sett listener
        toolbar = view.findViewById(R.id.forms_toolbar);
        if (toolbar != null) {
            toolbar.setNavigationOnClickListener(v -> Navigation.findNavController(view).navigateUp());
        }

        btnToggleHistory = view.findViewById(R.id.btn_toggle_history);
        if (btnToggleHistory != null) {
            btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility());
        }

        if (view instanceof ViewGroup) {
            LayoutTransition transition = ((ViewGroup) view).getLayoutTransition();
            if (transition == null) {
                transition = new LayoutTransition();
                ((ViewGroup) view).setLayoutTransition(transition);
            }
            transition.enableTransitionType(LayoutTransition.CHANGING);
        }

        if (formContainer == null) {
            formContainer = new LinearLayout(getContext());
        }

        if (getArguments() != null) {
            int argId = getArguments().getInt("formId", 0);
            if (argId != 0) formId = argId;
        }

        fetchFormStructure();

        return view;
    }

    // --- UI LOGIKK FOR DELT SKJERM ---

    private void expandFormModule() {
        if (historyWrapper != null && historyWrapper.getVisibility() == View.VISIBLE) {
            historyWrapper.setVisibility(View.GONE);
            if (btnToggleHistory != null) {
                btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
            }
        }
    }

    private void toggleHistoryVisibility() {
        if (historyWrapper == null || btnToggleHistory == null) return;

        if (historyWrapper.getVisibility() == View.VISIBLE) {
            historyWrapper.setVisibility(View.GONE);
            btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
        } else {
            historyWrapper.setVisibility(View.VISIBLE);
            btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
        }
    }

    private void attachInteractionListener(View view) {
        if (view == null) return;
        view.setOnTouchListener((v, event) -> {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                expandFormModule();
            }
            return false;
        });
        view.setOnFocusChangeListener((v, hasFocus) -> {
            if (hasFocus) {
                expandFormModule();
            }
        });
        if (view.isClickable()) {
            view.setOnClickListener(v -> expandFormModule());
        }
    }

    // ----------------------------------

    private void fetchFormStructure() {
        if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
        updateStatus("Laster skjema...");

        WordPressApiService api = RetrofitClient.getApiService();
        api.getForm(formId).enqueue(new retrofit2.Callback<GravityForm>() {
            @Override
            public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
                if (response.isSuccessful() && response.body() != null) {
                    currentForm = response.body();
                    if (getActivity() != null) {
                        getActivity().runOnUiThread(() -> {
                            if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
                            renderDynamicForm(currentForm);
                            fetchFormEntries();
                        });
                    }
                } else {
                    updateStatus("Feil ved lasting av skjema.");
                    if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
                }
            }

            @Override
            public void onFailure(retrofit2.Call<GravityForm> call, Throwable t) {
                updateStatus("Nettverksfeil (Skjema): " + t.getMessage());
                if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
            }
        });
    }

    private void renderDynamicForm(GravityForm form) {
        if (formContainer == null) return;
        formContainer.removeAllViews();
        fieldWrappers.clear();
        inputViews.clear();
        requiredFieldsMap.clear();
        fileUploads.clear();
        nestedEntries.clear();
        updateStatus("");

        // NYTT: Sett tittelen i Toolbaren i stedet for å legge til en TextView
        if (toolbar != null) {
            toolbar.setTitle(getCleanTitle(form.title));
        }

        if (historyWrapper != null) {
            historyWrapper.setVisibility(View.VISIBLE);
            if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
        }

        // Beskrivelse legges fortsatt inn som innhold
        if (form.description != null && !form.description.isEmpty()) {
            TextView formDesc = new TextView(getContext());
            String cleanDesc = form.description.replaceFirst("^\\d+\\.\\s*", "");
            formDesc.setText(cleanDesc);
            formDesc.setPadding(0, 0, 0, 40);
            formContainer.addView(formDesc);
        }

        if (form.fields == null) return;
        for (GravityField field : form.fields) {
            if ("hidden".equals(field.type) || field.isHidden || "hidden".equals(field.visibility)) {
                continue;
            }

            LinearLayout fieldWrapper = new LinearLayout(getContext());
            fieldWrapper.setOrientation(LinearLayout.VERTICAL);
            fieldWrapper.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            fieldWrapper.setPadding(0, 10, 0, 20);

            fieldWrappers.put(String.valueOf(field.id), fieldWrapper);

            if ("section".equals(field.type)) {
                addSectionHeader(fieldWrapper, field.label, field.description);
                formContainer.addView(fieldWrapper);
                continue;
            }

            if ("html".equals(field.type)) {
                if (field.content != null && !field.content.isEmpty()) {
                    TextView htmlView = new TextView(getContext());
                    htmlView.setText(Html.fromHtml(field.content, Html.FROM_HTML_MODE_COMPACT));
                    fieldWrapper.addView(htmlView);
                }
                formContainer.addView(fieldWrapper);
                continue;
            }

            TextView label = new TextView(getContext());
            String labelText = field.label;
            if (field.isRequired) labelText += " *";
            label.setText(labelText);
            label.setTextColor(Color.DKGRAY);
            label.setTypeface(null, Typeface.BOLD);
            label.setPadding(0, 10, 0, 5);
            fieldWrapper.addView(label);

            if ("form".equals(field.type)) {
                renderNestedFormField(fieldWrapper, field);
            }
            else if ("product".equals(field.type) && "calculation".equals(field.inputType)) {
                renderTotalSumField(fieldWrapper, field);
            }
            else if ("time".equals(field.type)) {
                renderTimeField(fieldWrapper, field, inputViews, requiredFieldsMap);
            } else if ("fileupload".equals(field.type)) {
                renderFileUploadField(fieldWrapper, field, inputViews, requiredFieldsMap, false);
            } else if (field.inputs != null && !field.inputs.isEmpty()) {
                if ("consent".equals(field.type)) {
                    renderConsentField(fieldWrapper, field, inputViews, requiredFieldsMap);
                } else if ("checkbox".equals(field.type) || "multi_choice".equals(field.type)) {
                    renderCheckboxField(fieldWrapper, field, inputViews, requiredFieldsMap);
                } else {
                    renderCompositeField(fieldWrapper, field, inputViews, requiredFieldsMap);
                }
            } else if ("radio".equals(field.type)) {
                renderRadioField(fieldWrapper, field, inputViews, requiredFieldsMap);
            } else if ("select".equals(field.type)) {
                renderSelectField(fieldWrapper, field, inputViews, requiredFieldsMap);
            } else if ("textarea".equals(field.type)) {
                renderTextAreaField(fieldWrapper, field, inputViews, requiredFieldsMap);
            } else if ("date".equals(field.type)) {
                renderDateField(fieldWrapper, field, inputViews, requiredFieldsMap);
            } else if ("consent".equals(field.type)) {
                renderConsentField(fieldWrapper, field, inputViews, requiredFieldsMap);
            } else {
                renderTextField(fieldWrapper, field, inputViews, requiredFieldsMap);
            }

            if (field.description != null && !field.description.isEmpty()) {
                TextView desc = new TextView(getContext());
                desc.setText(Html.fromHtml(field.description, Html.FROM_HTML_MODE_COMPACT));
                desc.setTextSize(12);
                desc.setTextColor(Color.GRAY);
                fieldWrapper.addView(desc);
            }

            formContainer.addView(fieldWrapper);
        }

        Button dynamicSubmit = new Button(getContext());
        dynamicSubmit.setText("Send inn skjema");
        dynamicSubmit.setTextColor(Color.WHITE);
        dynamicSubmit.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.setMargins(0, 60, 0, 20);
        dynamicSubmit.setLayoutParams(params);
        dynamicSubmit.setOnClickListener(v -> submitDynamicForm());
        formContainer.addView(dynamicSubmit);

        evaluateAllConditionalLogic();
    }

    // --- NESTED FORM LOGIKK ---

    private void renderNestedFormField(LinearLayout container, GravityField field) {
        nestedEntriesContainer = new LinearLayout(getContext());
        nestedEntriesContainer.setOrientation(LinearLayout.VERTICAL);
        nestedEntriesContainer.setPadding(0, 10, 0, 10);
        container.addView(nestedEntriesContainer);

        Button btnAdd = new Button(getContext());
        btnAdd.setText("Legg til vedlegg");
        btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
        btnAdd.setTextColor(Color.WHITE);
        btnAdd.setOnClickListener(v -> {
            expandFormModule();
            int childFormId = 18;
            if (field.gpnfForm != null) {
                try {
                    childFormId = Integer.parseInt(field.gpnfForm);
                } catch (NumberFormatException e) { e.printStackTrace(); }
            }
            openChildFormDialog(childFormId, field.id);
        });
        container.addView(btnAdd);

        EditText hiddenIds = new EditText(getContext());
        hiddenIds.setVisibility(View.GONE);
        inputViews.put(field.id, hiddenIds);
    }

    private void renderTotalSumField(LinearLayout container, GravityField field) {
        totalAmountView = new TextView(getContext());
        totalAmountView.setText("Kr 0,00");
        totalAmountView.setTextSize(18);
        totalAmountView.setTypeface(null, Typeface.BOLD);
        totalAmountView.setPadding(10, 10, 10, 10);
        container.addView(totalAmountView);
    }

    private void openChildFormDialog(int childFormId, String parentFieldId) {
        if (getActivity() == null) return;
        ProgressBar pBar = new ProgressBar(getContext());
        AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
                .setView(pBar)
                .setMessage("Laster skjema...")
                .setCancelable(false)
                .show();
        RetrofitClient.getApiService().getForm(childFormId).enqueue(new retrofit2.Callback<GravityForm>() {
            @Override
            public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
                loadingDialog.dismiss();
                if (response.isSuccessful() && response.body() != null) {
                    showChildFormDialog(response.body(), parentFieldId);
                } else {
                    Toast.makeText(getContext(), "Kunne ikke hente underskjema", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(retrofit2.Call<GravityForm> call, Throwable t) {
                loadingDialog.dismiss();
                Toast.makeText(getContext(), "Feil: " + t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void showChildFormDialog(GravityForm childForm, String parentFieldId) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        childInputViews.clear();
        childRequiredFieldsMap.clear();
        childFileUploads.clear();

        ScrollView scrollView = new ScrollView(getContext());
        LinearLayout layout = new LinearLayout(getContext());
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setPadding(30, 30, 30, 30);
        scrollView.addView(layout);
        for (GravityField field : childForm.fields) {
            if ("hidden".equals(field.type) || field.isHidden) continue;
            LinearLayout wrapper = new LinearLayout(getContext());
            wrapper.setOrientation(LinearLayout.VERTICAL);
            wrapper.setPadding(0, 10, 0, 20);

            TextView label = new TextView(getContext());
            String lText = field.label;
            if (field.isRequired) lText += " *";
            label.setText(lText);
            label.setTypeface(null, Typeface.BOLD);
            wrapper.addView(label);
            if ("fileupload".equals(field.type)) {
                renderFileUploadField(wrapper, field, childInputViews, childRequiredFieldsMap, true);
            } else if ("product".equals(field.type)) {
                EditText input = new EditText(getContext());
                input.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
                input.setHint("Kr 0.00");
                wrapper.addView(input);
                childInputViews.put(field.id, input);
                childRequiredFieldsMap.put(field.id, field.isRequired);
            } else {
                renderTextField(wrapper, field, childInputViews, childRequiredFieldsMap);
            }
            layout.addView(wrapper);
        }

        builder.setView(scrollView);
        builder.setPositiveButton("Legg til vedlegg", null);
        builder.setNegativeButton("Avbryt", (d, w) -> d.dismiss());
        AlertDialog dialog = builder.create();
        dialog.show();

        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
            submitChildForm(childForm.id, dialog, parentFieldId);
        });
    }

    private void submitChildForm(int childFormId, AlertDialog dialog, String parentFieldId) {
        JSONObject inputValues = new JSONObject();
        for (Map.Entry<String, View> entry : childInputViews.entrySet()) {
            String val = getInputValueGeneric(entry.getValue());
            if (!val.isEmpty()) {
                try {
                    inputValues.put("input_" + entry.getKey(), val);
                } catch (JSONException e) { e.printStackTrace(); }
            }
        }

        if (!childFileUploads.isEmpty()) {
            List<MultipartBody.Part> fileParts = new ArrayList<>();
            Map<String, RequestBody> textParts = new HashMap<>();

            try {
                JSONArray names = inputValues.names();
                if (names != null) {
                    for (int i = 0; i < names.length(); i++) {
                        String key = names.getString(i);
                        String val = inputValues.getString(key);
                        textParts.put(key, RequestBody.create(MultipartBody.FORM, val));
                    }
                }

                if (parentFieldId != null) {
                    textParts.put("gpnf_entry_nested_form_field", RequestBody.create(MultipartBody.FORM, parentFieldId));
                }

                for (Map.Entry<String, Uri> fileEntry : childFileUploads.entrySet()) {
                    String fieldId = fileEntry.getKey();
                    Uri uri = fileEntry.getValue();
                    if (uri != null) {
                        MultipartBody.Part part = getFilePart("input_" + fieldId, uri);
                        if (part != null) fileParts.add(part);
                    }
                }

                Toast.makeText(getContext(), "Laster opp vedlegg...", Toast.LENGTH_SHORT).show();
                RetrofitClient.getApiService().submitMultipartForm(childFormId, textParts, fileParts).enqueue(new retrofit2.Callback<JsonElement>() {
                    @Override
                    public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
                        if (response.isSuccessful() && response.body() != null) {
                            try {
                                JsonObject json = response.body().getAsJsonObject();
                                if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) {
                                    String entryId = json.has("entry_id") ? json.get("entry_id").getAsString() : "";
                                    String desc = getInputValueGeneric(childInputViews.get("3"));
                                    String price = getInputValueGeneric(childInputViews.get("4"));
                                    addNestedEntry(entryId, desc, price);
                                    dialog.dismiss();
                                } else {
                                    Toast.makeText(getContext(), "Ugyldig respons fra server", Toast.LENGTH_SHORT).show();
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                                Toast.makeText(getContext(), "Feil ved parsing av svar", Toast.LENGTH_SHORT).show();
                            }
                        } else {
                            Toast.makeText(getContext(), "Feil ved opplasting", Toast.LENGTH_SHORT).show();
                        }
                    }
                    @Override
                    public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) {
                        Toast.makeText(getContext(), "Nettverksfeil", Toast.LENGTH_SHORT).show();
                    }
                });
            } catch (Exception e) { e.printStackTrace(); }
        }
    }

    private void addNestedEntry(String entryId, String description, String price) {
        nestedEntries.add(new NestedEntry(entryId, description, price));
        refreshNestedList();
    }

    private void refreshNestedList() {
        if (nestedEntriesContainer == null) return;
        nestedEntriesContainer.removeAllViews();

        double total = 0;
        List<String> ids = new ArrayList<>();
        for (NestedEntry entry : nestedEntries) {
            ids.add(entry.id);
            String cleanPrice = entry.price.replaceAll("[^0-9,.]", "").replace(",", ".");
            try {
                if (!cleanPrice.isEmpty()) total += Double.parseDouble(cleanPrice);
            } catch (NumberFormatException e) { }

            LinearLayout row = new LinearLayout(getContext());
            row.setOrientation(LinearLayout.HORIZONTAL);
            row.setPadding(10, 10, 10, 10);

            TextView txt = new TextView(getContext());
            txt.setText(entry.description + " (" + entry.price + ")");
            txt.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1));

            row.addView(txt);
            nestedEntriesContainer.addView(row);
        }

        if (totalAmountView != null) {
            totalAmountView.setText("Totalt: Kr " + String.format("%.2f", total));
        }

        View hiddenField = inputViews.get("25");
        if (hiddenField instanceof EditText) {
            ((EditText)hiddenField).setText(TextUtils.join(",", ids));
        }
    }

    // --- FELLES METODER (FILE UPLOAD M/ CAMERA STØTTE) ---

    private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
        LinearLayout fileLayout = new LinearLayout(getContext());
        fileLayout.setOrientation(LinearLayout.HORIZONTAL);

        Button btnUpload = new Button(getContext());
        btnUpload.setText("Velg fil / Ta bilde");
        btnUpload.setOnClickListener(v -> {
            pendingFileFieldId = field.id;
            isSelectingForChild = isChild;
            expandFormModule();
            showFileSourceDialog();
        });
        TextView txtFileName = new TextView(getContext());
        txtFileName.setText("Ingen fil valgt");
        txtFileName.setPadding(20, 0, 0, 0);
        txtFileName.setTextColor(Color.GRAY);
        btnUpload.setTag(txtFileName);

        fileLayout.addView(btnUpload);
        fileLayout.addView(txtFileName);
        container.addView(fileLayout);

        viewsMap.put(field.id, btnUpload);
        reqMap.put(field.id, field.isRequired);
    }

    private void showFileSourceDialog() {
        String[] options = {"Ta bilde", "Velg fil"};
        new AlertDialog.Builder(getContext())
                .setTitle("Last opp vedlegg")
                .setItems(options, (dialog, which) -> {
                    if (which == 0) {
                        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
                                == PackageManager.PERMISSION_GRANTED) {
                            openCamera();
                        } else {
                            requestPermissionLauncher.launch(Manifest.permission.CAMERA);
                        }
                    } else {
                        if (filePickerLauncher != null) {
                            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                            intent.setType("*/*");
                            String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
                            intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
                            filePickerLauncher.launch(intent);
                        }
                    }
                })
                .show();
    }

    private void openCamera() {
        currentPhotoUri = createImageUri();
        if (currentPhotoUri != null && takePictureLauncher != null) {
            try {
                takePictureLauncher.launch(currentPhotoUri);
            } catch (Exception e) {
                Toast.makeText(getContext(), "Kunne ikke starte kamera: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Camera launch failed", e);
            }
        } else {
            Toast.makeText(getContext(), "Kunne ikke opprette bildefil", Toast.LENGTH_SHORT).show();
        }
    }

    private Uri createImageUri() {
        try {
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
            String imageFileName = "JPEG_" + timeStamp + "_";
            File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            File image = File.createTempFile(imageFileName, ".jpg", storageDir);
            return FileProvider.getUriForFile(requireContext(), "com.kbs.kbsintranett.fileprovider", image);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
        if (isChild) {
            childFileUploads.put(fieldId, uri);
        } else {
            fileUploads.put(fieldId, uri);
        }

        Map<String, View> targetMap = isChild ? childInputViews : inputViews;
        View view = targetMap.get(fieldId);
        if (view instanceof Button) {
            TextView txtView = (TextView) view.getTag();
            if (txtView != null) {
                txtView.setText(getFileName(uri));
                txtView.setTextColor(Color.BLACK);
            }
        }
    }

    private String getFileName(Uri uri) {
        String result = null;
        if (uri.getScheme().equals("content")) {
            try (Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null)) {
                if (cursor != null && cursor.moveToFirst()) {
                    int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                    if(index >= 0) result = cursor.getString(index);
                }
            } catch (Exception e) {}
        }
        if (result == null) {
            result = uri.getPath();
            int cut = result.lastIndexOf('/');
            if (cut != -1) result = result.substring(cut + 1);
        }
        return result;
    }

    private String getCleanTitle(String title) {
        if (title == null) return "";
        Matcher m = TITLE_PATTERN.matcher(title.trim());
        if (m.find()) {
            return m.group(2);
        }
        return title;
    }

    // --- STANDARD RENDER METODER ---

    private void renderTimeField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        EditText timeInput = new EditText(getContext());
        timeInput.setFocusable(false);
        timeInput.setClickable(true);
        timeInput.setHint("00:00");
        timeInput.setOnClickListener(v -> {
            expandFormModule();
            Calendar mcurrentTime = Calendar.getInstance();
            int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
            int minute = mcurrentTime.get(Calendar.MINUTE);
            new TimePickerDialog(getContext(), (timePicker, selectedHour, selectedMinute) -> {
                timeInput.setText(String.format("%02d:%02d", selectedHour, selectedMinute));
                evaluateAllConditionalLogic();
            }, hour, minute, true).show();
        });
        container.addView(timeInput);
        views.put(field.id, timeInput);
        req.put(field.id, field.isRequired);
    }

    private void renderTextField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        EditText input = new EditText(getContext());
        input.setPadding(30, 30, 30, 30);
        input.setBackgroundResource(android.R.drawable.edit_text);

        if ("number".equals(field.type) || "phone".equals(field.type)) {
            input.setInputType(InputType.TYPE_CLASS_PHONE);
        } else if ("email".equals(field.type)) {
            input.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
        } else {
            input.setInputType(InputType.TYPE_CLASS_TEXT);
        }

        if (views == inputViews) {
            UserManager user = UserManager.getInstance();
            String lowerLabel = field.label.toLowerCase();
            if (lowerLabel.contains("e-post")) input.setText(user.getUserEmail());
            if (lowerLabel.contains("navn") || lowerLabel.contains("melder")) input.setText(user.getUserDisplayName());
            if (lowerLabel.contains("stilling")) input.setText(user.getStilling());
            if (lowerLabel.contains("mobil")) input.setText(user.getMobiltelefon());
        }

        input.addTextChangedListener(new TextWatcher() {
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
            public void onTextChanged(CharSequence s, int start, int before, int count) {}
            public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
        });
        attachInteractionListener(input);

        container.addView(input);
        views.put(field.id, input);
        req.put(field.id, field.isRequired);
    }

    private void renderTextAreaField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        EditText input = new EditText(getContext());
        input.setBackgroundResource(android.R.drawable.edit_text);
        input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
        input.setMinLines(3);
        input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);

        attachInteractionListener(input);

        container.addView(input);
        views.put(field.id, input);
        req.put(field.id, field.isRequired);
    }

    private void renderRadioField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        RadioGroup group = new RadioGroup(getContext());
        if (field.choices != null) {
            for (GravityField.Choice choice : field.choices) {
                RadioButton rb = new RadioButton(getContext());
                rb.setText(choice.text);
                rb.setTag(choice.value);
                rb.setOnClickListener(v -> {
                    expandFormModule();
                    evaluateAllConditionalLogic();
                });
                group.addView(rb);
            }
        }
        group.setOnCheckedChangeListener((g, i) -> {
            expandFormModule();
            evaluateAllConditionalLogic();
        });
        container.addView(group);
        views.put(field.id, group);
        req.put(field.id, field.isRequired);
    }

    private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        Spinner spinner = new Spinner(getContext());
        spinner.setOnTouchListener((v, event) -> {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                expandFormModule();
            }
            return false;
        });
        List<String> labels = new ArrayList<>();
        labels.add("- Velg -");
        if (field.choices != null) {
            for (GravityField.Choice c : field.choices) labels.add(c.text);
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, labels);
        spinner.setAdapter(adapter);
        container.addView(spinner);
        views.put(field.id, spinner);
        req.put(field.id, field.isRequired);
    }

    private void renderConsentField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        CheckBox checkBox = new CheckBox(getContext());
        String cbText = (field.checkboxLabel != null && !field.checkboxLabel.isEmpty()) ? field.checkboxLabel : field.label;
        checkBox.setText(cbText);
        String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;

        checkBox.setTag("1");
        checkBox.setOnCheckedChangeListener((b, c) -> {
            expandFormModule();
            evaluateAllConditionalLogic();
        });
        container.addView(checkBox);
        views.put(inputId, checkBox);
        req.put(inputId, field.isRequired);
    }

    private void renderCheckboxField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        if (field.inputs != null) {
            for (int i = 0; i < field.inputs.size(); i++) {
                GravityField inputDef = field.inputs.get(i);
                CheckBox checkBox = new CheckBox(getContext());
                checkBox.setText(inputDef.label);

                String value = "1";
                if (field.choices != null && i < field.choices.size()) {
                    value = field.choices.get(i).value;
                }
                checkBox.setTag(value);
                checkBox.setOnCheckedChangeListener((b, c) -> {
                    expandFormModule();
                    evaluateAllConditionalLogic();
                });
                container.addView(checkBox);
                views.put(inputDef.id, checkBox);
                req.put(inputDef.id, false);
            }
        }
    }

    private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        EditText dateInput = new EditText(getContext());
        if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) {
            SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
            dateInput.setText(df.format(new Date()));

            dateInput.setFocusable(false);
            dateInput.setClickable(false);
            dateInput.setEnabled(false);
            dateInput.setTextColor(Color.BLACK);
        } else {
            dateInput.setFocusable(false);
            dateInput.setClickable(true);
            dateInput.setHint("dd.mm.yyyy");
            dateInput.setOnClickListener(v -> {
                expandFormModule();
                Calendar c = Calendar.getInstance();
                new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
                    dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
                    evaluateAllConditionalLogic();
                }, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH)).show();
            });
        }

        dateInput.setPadding(30, 30, 30, 30);
        dateInput.setBackgroundResource(android.R.drawable.edit_text);

        container.addView(dateInput);
        views.put(field.id, dateInput);
        req.put(field.id, field.isRequired);
    }

    private void renderCompositeField(LinearLayout container, GravityField parentField, Map<String, View> views, Map<String, Boolean> req) {
        UserManager user = UserManager.getInstance();
        boolean isPersonalia = (formId == ID_ANSATTEOPPLYSNINGER);

        List<GravityField> inputs = new ArrayList<>(parentField.inputs);
        if ("address".equals(parentField.type)) {
            Collections.sort(inputs, (f1, f2) -> Integer.compare(getAddressScore(f1.label), getAddressScore(f2.label)));
        }

        for (GravityField subField : inputs) {
            if (subField.isHidden || "hidden".equals(subField.visibility)) continue;
            TextView subLabel = new TextView(getContext());
            String subLabelText = subField.label;
            boolean isSubRequired = parentField.isRequired;
            if ("address".equals(parentField.type) && subField.id.endsWith(".2")) {
                isSubRequired = false;
            }
            if (isSubRequired) subLabelText += " *";

            subLabel.setText(subLabelText);
            subLabel.setTextColor(Color.GRAY);
            subLabel.setTextSize(12);
            subLabel.setPadding(0, 10, 0, 0);
            container.addView(subLabel);

            EditText subInput = new EditText(getContext());
            subInput.setPadding(30, 30, 30, 30);
            subInput.setBackgroundResource(android.R.drawable.edit_text);
            subInput.setInputType(InputType.TYPE_CLASS_TEXT);
            if (isPersonalia && parentField.label.toLowerCase().contains("navn") && !parentField.label.toLowerCase().contains("pårørende")) {
                String lowerSub = subField.label.toLowerCase();
                if (lowerSub.contains("fornavn")) subInput.setText(user.getFirstName());
                else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
            }

            attachInteractionListener(subInput);
            container.addView(subInput);
            views.put(subField.id, subInput);
            req.put(subField.id, isSubRequired);
        }
    }

    private void addSectionHeader(LinearLayout container, String title, String descText) {
        TextView sectionHeader = new TextView(getContext());
        sectionHeader.setText(title);
        sectionHeader.setTextSize(18);
        sectionHeader.setTypeface(null, Typeface.BOLD);
        sectionHeader.setTextColor(Color.parseColor("#0069B3"));
        sectionHeader.setPadding(0, 20, 0, 5);
        container.addView(sectionHeader);
        if (descText != null && !descText.isEmpty()) {
            TextView desc = new TextView(getContext());
            desc.setText(Html.fromHtml(descText, Html.FROM_HTML_MODE_COMPACT));
            desc.setTextSize(12);
            desc.setTextColor(Color.GRAY);
            container.addView(desc);
        }

        View line = new View(getContext());
        line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 2));
        line.setBackgroundColor(Color.LTGRAY);
        line.setPadding(0,0,0,20);
        container.addView(line);
    }

    private int getAddressScore(String label) {
        if (label == null) return 99;
        String l = label.toLowerCase();
        if (l.contains("adresselinje 1")) return 1;
        if (l.contains("adresselinje 2")) return 2;
        if (l.contains("postnummer") || l.contains("zip")) return 3;
        if (l.contains("poststed") || l.contains("city")) return 4;
        if (l.contains("land") || l.contains("country")) return 5;
        return 99;
    }

    private void evaluateAllConditionalLogic() {
        if (currentForm == null || currentForm.fields == null) return;
        for (GravityField field : currentForm.fields) {
            if (field.conditionalLogic == null) {
                setViewVisibility(field.id, true);
                continue;
            }

            boolean isMatch = evaluateLogic(field.conditionalLogic);
            boolean show = "show".equalsIgnoreCase(field.conditionalLogic.actionType);
            boolean shouldBeVisible = (show && isMatch) || (!show && !isMatch);
            setViewVisibility(field.id, shouldBeVisible);
        }
    }

    private boolean evaluateLogic(GravityField.ConditionalLogic logic) {
        if (logic.rules == null || logic.rules.isEmpty()) return true;
        boolean isAll = "all".equalsIgnoreCase(logic.logicType);
        boolean aggregatedResult = isAll;

        for (GravityField.Rule rule : logic.rules) {
            String val = getInputValue(rule.fieldId);
            boolean ruleMatch = checkRule(val, rule.operator, rule.value);

            if (isAll) {
                aggregatedResult = aggregatedResult && ruleMatch;
                if (!aggregatedResult) break;
            } else {
                aggregatedResult = aggregatedResult ||
                        ruleMatch;
                if (aggregatedResult) break;
            }
        }
        return aggregatedResult;
    }

    private boolean checkRule(String actualValue, String operator, String targetValue) {
        if (actualValue == null) actualValue = "";
        if (targetValue == null) targetValue = "";

        switch (operator.toLowerCase()) {
            case "is": return actualValue.equalsIgnoreCase(targetValue);
            case "isnot": return !actualValue.equalsIgnoreCase(targetValue);
            case "contains": return actualValue.toLowerCase().contains(targetValue.toLowerCase());
            case "starts_with": return actualValue.toLowerCase().startsWith(targetValue.toLowerCase());
            case "ends_with": return actualValue.toLowerCase().endsWith(targetValue.toLowerCase());
            default: return false;
        }
    }

    private String getInputValue(String fieldId) {
        View view = inputViews.get(fieldId);
        return getInputValueGeneric(view);
    }

    private String getInputValueGeneric(View view) {
        if (view == null) return "";
        if (view instanceof EditText) return ((EditText) view).getText().toString();
        if (view instanceof RadioGroup) {
            int id = ((RadioGroup) view).getCheckedRadioButtonId();
            if (id != -1) {
                View rb = view.findViewById(id);
                if (rb != null && rb.getTag() != null) return rb.getTag().toString();
            }
        }
        if (view instanceof Spinner) {
            if (((Spinner) view).getSelectedItemPosition() == 0) return "";
            Object item = ((Spinner) view).getSelectedItem();
            return item != null ? item.toString() : "";
        }
        if (view instanceof CheckBox) {
            CheckBox cb = (CheckBox) view;
            if (cb.isChecked()) {
                return cb.getTag() != null ?
                        cb.getTag().toString() : "1";
            }
            return "";
        }
        return "";
    }

    private void setViewVisibility(String fieldId, boolean visible) {
        View wrapper = fieldWrappers.get(fieldId);
        if (wrapper != null) {
            wrapper.setVisibility(visible ? View.VISIBLE : View.GONE);
        }
    }

    // --- SUBMISSION ---

    private void submitDynamicForm() {
        JSONObject inputValues = new JSONObject();
        boolean hasValues = false;

        Log.d(TAG, "submitDynamicForm: Starting validation...");

        for (Map.Entry<String, View> entry : inputViews.entrySet()) {
            String fieldId = entry.getKey();
            View view = entry.getValue();

            View wrapper = fieldWrappers.get(fieldId);
            if (wrapper == null) {
                if (!view.isShown()) continue;
            } else {
                if (wrapper.getVisibility() != View.VISIBLE) continue;
            }

            String val = getInputValueGeneric(view);
            Boolean req = requiredFieldsMap.get(fieldId);
            if (req != null && req && val.isEmpty() && !(view instanceof Button)) {
                Log.d(TAG, "Validation failed for field " + fieldId);
                if (view instanceof EditText) {
                    ((EditText)view).setError("Må fylles ut");
                    view.requestFocus();
                } else {
                    Toast.makeText(getContext(), "Fyll ut alle felt", Toast.LENGTH_SHORT).show();
                }
                return;
            }
            if (!val.isEmpty()) {
                try {
                    GravityField fieldDef = getGravityFieldById(fieldId);
                    if (fieldDef != null && "date".equals(fieldDef.type)) {
                        val = formatDateForApi(val);
                    }

                    inputValues.put("input_" + fieldId, val);
                    hasValues = true;
                } catch (JSONException e) {}
            }
        }

        if (!hasValues && fileUploads.isEmpty()) {
            Log.d(TAG, "Submit aborted: Form is empty");
            Toast.makeText(getContext(), "Skjemaet er tomt", Toast.LENGTH_SHORT).show();
            return;
        }

        updateStatus("Sender inn...");
        String cookie = UserManager.getInstance().getCookie();
        Log.d(TAG, "Preparing submission payload: " + inputValues.toString());

        if (!fileUploads.isEmpty()) {
            Log.d(TAG, "Submitting as Multipart...");
            sendMultipart(inputValues);
        } else {
            Log.d(TAG, "Submitting as JSON...");
            RequestBody body = RequestBody.create(MediaType.parse("application/json"), inputValues.toString());
            String url = BASE_URL_GF + "/forms/" + formId + "/submissions";
            Request request = new Request.Builder().url(url).post(body).header("Cookie", cookie).build();
            client.newCall(request).enqueue(new okhttp3.Callback() {
                public void onFailure(okhttp3.Call call, IOException e) {
                    Log.e(TAG, "JSON submit failed", e);
                    updateStatus("Feil: " + e.getMessage());
                }
                public void onResponse(okhttp3.Call call, Response response) {
                    Log.d(TAG, "JSON response code: " + response.code());
                    if (response.isSuccessful()) {
                        if (getActivity() != null) getActivity().runOnUiThread(() -> {
                            Toast.makeText(getContext(), "Sendt!", Toast.LENGTH_LONG).show();
                            fetchFormEntries();
                            updateStatus("OK");
                            clearInputs();
                        });
                    } else {
                        try {
                            String errBody = response.body() != null ? response.body().string() : "No body";
                            Log.e(TAG, "Server error body: " + errBody);
                            updateStatus("Feil (" + response.code() + "): " + errBody);
                        } catch(Exception e){}
                    }
                }
            });
        }
    }

    private String formatDateForApi(String dateStr) {
        if (dateStr == null || dateStr.isEmpty()) return "";
        try {
            SimpleDateFormat displayFormat = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
            Date date = displayFormat.parse(dateStr);
            SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
            return apiFormat.format(date);
        } catch (Exception e) {
            return dateStr;
        }
    }

    private GravityField getGravityFieldById(String id) {
        if (currentForm == null || currentForm.fields == null) return null;
        for (GravityField f : currentForm.fields) {
            if (f.id.equals(id)) return f;
            if (f.inputs != null) {
                for (GravityField sub : f.inputs) {
                    if (sub.id.equals(id)) return sub;
                }
            }
        }
        return null;
    }

    private void sendMultipart(JSONObject inputValues) {
        List<MultipartBody.Part> fileParts = new ArrayList<>();
        Map<String, RequestBody> textParts = new HashMap<>();
        try {
            JSONArray names = inputValues.names();
            if (names != null) {
                for(int i=0; i<names.length(); i++) {
                    String k = names.getString(i);
                    textParts.put(k, RequestBody.create(MultipartBody.FORM, inputValues.getString(k)));
                }
            }
            for (Map.Entry<String, Uri> entry : fileUploads.entrySet()) {
                MultipartBody.Part part = getFilePart("input_" + entry.getKey(), entry.getValue());
                if (part != null) fileParts.add(part);
            }
            RetrofitClient.getApiService().submitMultipartForm(formId, textParts, fileParts).enqueue(new retrofit2.Callback<JsonElement>() {
                public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
                    if (response.isSuccessful()) {
                        if (getActivity() != null) getActivity().runOnUiThread(() -> {
                            Toast.makeText(getContext(), "Sendt!", Toast.LENGTH_LONG).show();
                            fetchFormEntries();
                            updateStatus("OK");
                            clearInputs();
                        });
                    } else {
                        updateStatus("Feil: " + response.code());
                    }
                }
                public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) { updateStatus("Feil: " + t.getMessage()); }
            });
        } catch (Exception e) {}
    }

    private MultipartBody.Part getFilePart(String partName, Uri uri) {
        try {
            InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
            String fileName = getFileName(uri);
            RequestBody requestBody = new RequestBody() {
                @Override public MediaType contentType() { return MediaType.parse("application/octet-stream");
                }
                @Override public void writeTo(BufferedSink sink) throws IOException {
                    try (Source source = Okio.source(inputStream)) { sink.writeAll(source);
                    }
                }
            };
            return MultipartBody.Part.createFormData(partName, fileName, requestBody);
        } catch (Exception e) { return null;
        }
    }

    private void fetchFormEntries() {
        UserManager user = UserManager.getInstance();
        String cookie = user.getCookie();
        int userId = user.getUserId();

        if (cookie == null) return;
        String searchJson = "{\"field_filters\":[{\"key\":\"created_by\",\"value\":\"" + userId + "\"}]}";
        String encodedSearch = "";
        try {
            encodedSearch = URLEncoder.encode(searchJson, "UTF-8");
        } catch (UnsupportedEncodingException e) { e.printStackTrace(); }

        String url = BASE_URL_GF + "/entries?form_ids=" + formId + "&search=" + encodedSearch;
        Request request = new Request.Builder().url(url).header("Cookie", cookie).build();

        client.newCall(request).enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(@NonNull okhttp3.Call call, @NonNull IOException e) {
                Log.e(TAG, "Kunne ikke hente historikk", e);
            }

            @Override
            public void onResponse(@NonNull okhttp3.Call call, @NonNull Response response) throws IOException {
                if (response.isSuccessful()) {
                    String jsonStr = response.body().string();
                    try {
                        JSONObject json = new JSONObject(jsonStr);
                        if (json.has("entries")) {
                            JSONArray entries = json.getJSONArray("entries");
                            if (getActivity() != null) {
                                getActivity().runOnUiThread(() -> {
                                    showHistory(entries);
                                    if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0)
                                    {
                                        try {
                                            prefillFormFromHistory(entries.getJSONObject(0));
                                        } catch (JSONException e) { e.printStackTrace(); }
                                    }
                                });
                            }
                        }
                    } catch (JSONException e) { e.printStackTrace();
                    }
                }
            }
        });
    }

    private void showHistory(JSONArray entries) {
        if (historyContainer == null) return;
        historyContainer.removeAllViews();

        if (entries.length() == 0) {
            if (lblHistory != null) lblHistory.setVisibility(View.GONE);
            return;
        } else {
            if (lblHistory != null) lblHistory.setVisibility(View.VISIBLE);
        }

        try {
            int count = Math.min(entries.length(), 20);
            for (int i = 0; i < count; i++) {
                JSONObject entry = entries.getJSONObject(i);
                String date = entry.optString("date_created");

                String titleText = "Innsendt: " + date;
                TextView item = new TextView(getContext());
                item.setText(titleText);
                item.setPadding(10, 20, 10, 20);
                item.setBackgroundResource(android.R.drawable.list_selector_background);
                item.setTextSize(14);
                item.setOnClickListener(v -> showEntryDetails(entry));
                View line = new View(getContext());
                line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
                line.setBackgroundColor(Color.LTGRAY);

                historyContainer.addView(item);
                historyContainer.addView(line);
            }
        } catch (JSONException e) { e.printStackTrace();
        }
    }

    private void showEntryDetails(JSONObject entry) {
        if (formId == ID_REFUSJON_UTLEGG) {
            Log.d(TAG, "Form 16 detected. Checking for child entries...");
            String nestedIds = entry.optString("25");

            if (!nestedIds.isEmpty()) {
                Log.d(TAG, "Nested IDs found: " + nestedIds);
                List<String> ids = new ArrayList<>();

                if (nestedIds.startsWith("[") && nestedIds.endsWith("]")) {
                    try {
                        JSONArray jsonArray = new JSONArray(nestedIds);
                        for(int i=0; i<jsonArray.length(); i++) {
                            ids.add(jsonArray.getString(i));
                        }
                    } catch(JSONException e) {
                        Log.e(TAG, "Failed to parse nested IDs as JSON array", e);
                    }
                } else {
                    for (String id : nestedIds.split(",")) {
                        ids.add(id.trim());
                    }
                }

                if (!ids.isEmpty()) {
                    AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
                            .setMessage("Henter vedleggsdetaljer...")
                            .setCancelable(false)
                            .show();

                    StringBuilder accumulatedHtml = new StringBuilder();
                    StringBuilder accumulatedText = new StringBuilder();

                    appendBasicInfo(entry, accumulatedHtml, accumulatedText);

                    fetchChildEntriesRecursive(ids, 0, accumulatedHtml, accumulatedText, loadingDialog);
                    return;
                }
            }
        }

        StringBuilder htmlBuilder = new StringBuilder();
        StringBuilder textBuilder = new StringBuilder();
        appendBasicInfo(entry, htmlBuilder, textBuilder);
        showFinalDialog(htmlBuilder, textBuilder);
    }

    private void appendBasicInfo(JSONObject entry, StringBuilder html, StringBuilder text) {
        try {
            String date = entry.optString("date_created");
            html.append("<b>Innsendt:</b> ").append(date).append("<br><br>");
            text.append("Innsendt: ").append(date).append("\n\n");

            if (currentForm != null && currentForm.fields != null) {
                for (GravityField field : currentForm.fields) {
                    if ("section".equals(field.type) || "html".equals(field.type) || "captcha".equals(field.type)) continue;
                    if (formId == ID_REFUSJON_UTLEGG && "25".equals(field.id)) continue;

                    String value = "";
                    if (field.inputs != null && !field.inputs.isEmpty()) {
                        for (GravityField input : field.inputs) {
                            String subVal = entry.optString(input.id);
                            if (!subVal.isEmpty()) value += " " + subVal;
                        }
                    } else {
                        value = entry.optString(String.valueOf(field.id));
                    }

                    if (!value.trim().isEmpty()) {
                        if ("fileupload".equals(field.type)) {
                            String cleanUrl = extractUrl(value);
                            if (cleanUrl.startsWith("http")) {
                                html.append("<b>").append(field.label).append(":</b><br>")
                                        .append("<a href=\"").append(cleanUrl).append("\">Åpne fil</a><br><br>");
                                text.append(field.label).append(":\n").append(cleanUrl).append("\n\n");
                            } else {
                                html.append("<b>").append(field.label).append(":</b><br>").append(value).append("<br><br>");
                                text.append(field.label).append(":\n").append(value).append("\n\n");
                            }
                        } else {
                            html.append("<b>").append(field.label).append(":</b><br>").append(value).append("<br><br>");
                            text.append(field.label).append(":\n").append(value).append("\n\n");
                        }
                    }
                }
            }
        } catch (Exception e) {}
    }

    private void fetchChildEntriesRecursive(List<String> ids, int index, StringBuilder html, StringBuilder text, AlertDialog loader) {
        if (index >= ids.size()) {
            loader.dismiss();
            showFinalDialog(html, text);
            return;
        }

        String entryId = ids.get(index);
        RetrofitClient.getApiService().getSingleEntry(entryId).enqueue(new retrofit2.Callback<JsonElement>() {
            @Override
            public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
                if (response.isSuccessful() && response.body() != null) {
                    try {
                        JsonObject json = response.body().getAsJsonObject();
                        String desc = json.has("3") ? json.get("3").getAsString() : "Uten beskrivelse";
                        String price = json.has("4") ? json.get("4").getAsString() : "";

                        html.append("<b>Vedlegg ").append(index + 1).append(":</b><br>");
                        text.append("Vedlegg ").append(index + 1).append(":\n");

                        html.append(desc).append(" (").append(price).append(")<br>");
                        text.append(desc).append(" (").append(price).append(")\n");

                        if (json.has("1")) {
                            JsonElement fileEl = json.get("1");
                            if (fileEl.isJsonArray()) {
                                JsonArray arr = fileEl.getAsJsonArray();
                                for (int i = 0; i < arr.size(); i++) {
                                    String url = arr.get(i).getAsString().replace("\\/", "/");
                                    html.append("<a href=\"").append(url).append("\">Åpne fil ").append(i+1).append("</a><br>");
                                    text.append(url).append("\n");
                                }
                            } else {
                                String rawString = fileEl.getAsString();
                                if (rawString.startsWith("[") && rawString.endsWith("]")) {
                                    try {
                                        JSONArray arr = new JSONArray(rawString);
                                        for (int i = 0; i < arr.length(); i++) {
                                            String url = arr.getString(i).replace("\\/", "/");
                                            html.append("<a href=\"").append(url).append("\">Åpne fil ").append(i+1).append("</a><br>");
                                            text.append(url).append("\n");
                                        }
                                    } catch (JSONException ex) {
                                        String clean = extractUrl(rawString);
                                        html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
                                        text.append(clean).append("\n");
                                    }
                                } else {
                                    String clean = extractUrl(rawString);
                                    if(clean.startsWith("http")) {
                                        html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
                                        text.append(clean).append("\n");
                                    }
                                }
                            }
                        }
                        html.append("<br>");
                        text.append("\n");

                    } catch (Exception e) {
                        Log.e(TAG, "Error parsing child entry", e);
                    }
                }
                fetchChildEntriesRecursive(ids, index + 1, html, text, loader);
            }

            @Override
            public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) {
                fetchChildEntriesRecursive(ids, index + 1, html, text, loader);
            }
        });
    }

    private void showFinalDialog(StringBuilder htmlBuilder, StringBuilder textBuilder) {
        ScrollView scroll = new ScrollView(getContext());
        TextView text = new TextView(getContext());
        text.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
        text.setText(Html.fromHtml(htmlBuilder.toString(), Html.FROM_HTML_MODE_COMPACT));
        text.setPadding(40, 40, 40, 40);
        scroll.addView(text);

        new AlertDialog.Builder(getContext())
                .setTitle("Detaljer")
                .setView(scroll)
                .setPositiveButton("Lukk", null)
                .setNeutralButton("Del", (d, w) -> shareEntryDetails(textBuilder.toString()))
                .create()
                .show();
    }

    private String extractUrl(String rawValue) {
        if (rawValue == null) return "";
        String clean = rawValue.replace("[", "")
                .replace("]", "")
                .replace("\"", "")
                .replace("\\/", "/");
        return clean.trim();
    }

    private void shareEntryDetails(String text) {
        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_TEXT, text);
        sendIntent.setType("text/plain");

        Intent shareIntent = Intent.createChooser(sendIntent, "Del innsending via...");
        startActivity(shareIntent);
    }

    private void prefillFormFromHistory(JSONObject latestEntry) {
        if (latestEntry == null) return;
        for (Map.Entry<String, View> entry : inputViews.entrySet()) {
            String fieldId = entry.getKey();
            View view = entry.getValue();

            if (latestEntry.has(fieldId)) {
                String value = latestEntry.optString(fieldId);
                if (value == null || value.isEmpty()) continue;

                if (view instanceof EditText) {
                    ((EditText) view).setText(value);
                } else if (view instanceof RadioGroup) {
                    RadioGroup group = (RadioGroup) view;
                    for (int i = 0; i < group.getChildCount(); i++) {
                        View child = group.getChildAt(i);
                        if (child instanceof RadioButton) {
                            Object tag = child.getTag();
                            if (tag != null && tag.toString().equalsIgnoreCase(value)) {
                                ((RadioButton) child).setChecked(true);
                                break;
                            }
                        }
                    }
                } else if (view instanceof CheckBox) {
                    if ("1".equals(value) || "true".equalsIgnoreCase(value) || ((CheckBox)view).getText().toString().equals(value)) {
                        ((CheckBox) view).setChecked(true);
                    }
                }
            }
        }
        updateStatus("Skjemaet er forhåndsutfylt fra din siste innsending.");
        evaluateAllConditionalLogic();
    }

    private void clearInputs() {
        for (View view : inputViews.values()) {
            if (view instanceof EditText) {
                ((EditText) view).setText("");
            } else if (view instanceof CheckBox) {
                ((CheckBox) view).setChecked(false);
            } else if (view instanceof RadioGroup) {
                ((RadioGroup) view).clearCheck();
            } else if (view instanceof Button) {
                Object tag = view.getTag();
                if (tag instanceof TextView) {
                    ((TextView) tag).setText("Ingen fil valgt");
                }
            }
        }
        fileUploads.clear();
        nestedEntries.clear();
        if (nestedEntriesContainer != null) nestedEntriesContainer.removeAllViews();
        if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
    }

    private static class NestedEntry {
        String id;
        String description;
        String price;
        NestedEntry(String id, String d, String p) { this.id = id; this.description = d; this.price = p;
        }
    }

    private void updateStatus(String msg) {
        if (getActivity() != null && txtStatus != null) {
            getActivity().runOnUiThread(() -> txtStatus.setText(msg));
        }
    }
}