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.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;

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

    private static final int ID_ANSATTEOPPLYSNINGER = 1;
    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 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<>();

    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;

    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);
                    }
                }
        );
        requestPermissionLauncher = registerForActivityResult(
                new ActivityResultContracts.RequestPermission(),
                isGranted -> {
                    if (isGranted) openCamera();
                    else Toast.makeText(getContext(), "Kameratillatelse trengs.", Toast.LENGTH_SHORT).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);
        btnToggleHistory = view.findViewById(R.id.btn_toggle_history);

        if (btnToggleHistory != null) btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility());

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

        fetchFormStructure();
        return view;
    }

    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 fetchFormStructure() {
        if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
        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();
                        });
                    }
                }
            }
            @Override public void onFailure(retrofit2.Call<GravityForm> call, Throwable t) {
                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();

        // 1. OPPSETT AV TOOLBAR (MainActivity sin toolbar)
        if (getActivity() instanceof AppCompatActivity) {
            AppCompatActivity activity = (AppCompatActivity) getActivity();
            if (activity.getSupportActionBar() != null) {
                activity.getSupportActionBar().setTitle("Fyll ut skjema");
                activity.getSupportActionBar().setDisplayHomeAsUpEnabled(false); // Fjerner pil tilbake
            }
        }

        // 2. OVERSKRIFT I SKJEMAET
        TextView headerTitle = new TextView(getContext());
        headerTitle.setText("Fyll ut " + getCleanTitle(form.title));
        headerTitle.setTextSize(22); // Rettet fra 22sp til 22
        headerTitle.setTypeface(null, Typeface.BOLD);
        headerTitle.setTextColor(Color.BLACK);
        headerTitle.setPadding(0, 10, 0, 30);
        formContainer.addView(headerTitle);

        if (form.description != null && !form.description.isEmpty()) {
            TextView formDesc = new TextView(getContext());
            formDesc.setText(form.description.replaceFirst("^\\d+\\.\\s*", ""));
            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 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"));
        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();
    }

    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 -> {
            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) {
        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);
                }
            }
            @Override public void onFailure(retrofit2.Call<GravityForm> call, Throwable t) { loadingDialog.dismiss(); }
        });
    }

    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());
            label.setText(field.label + (field.isRequired ? " *" : ""));
            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(); }
            }
        }

        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);
                    textParts.put(key, RequestBody.create(MultipartBody.FORM, inputValues.getString(key)));
                }
            }
            if (parentFieldId != null) textParts.put("gpnf_entry_nested_form_field", RequestBody.create(MultipartBody.FORM, parentFieldId));

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

            Toast.makeText(getContext(), "Laster opp...", 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) {
                        JsonObject json = response.body().getAsJsonObject();
                        if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) {
                            String entryId = json.get("entry_id").getAsString();
                            String desc = getInputValueGeneric(childInputViews.get("3"));
                            String price = getInputValueGeneric(childInputViews.get("4"));
                            addNestedEntry(entryId, desc, price);
                            dialog.dismiss();
                        }
                    }
                }
                @Override public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) {}
            });
        } 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 ignored) {}

            TextView txt = new TextView(getContext());
            txt.setText(entry.description + " (" + entry.price + ")");
            txt.setPadding(10, 10, 10, 10);
            nestedEntriesContainer.addView(txt);
        }
        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));
    }

    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 / Kamera");
        btnUpload.setOnClickListener(v -> {
            pendingFileFieldId = field.id;
            isSelectingForChild = isChild;
            showFileSourceDialog();
        });
        TextView txtFileName = new TextView(getContext());
        txtFileName.setText("Ingen valgt");
        txtFileName.setPadding(20, 0, 0, 0);
        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").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 {
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.setType("*/*");
                filePickerLauncher.launch(intent);
            }
        }).show();
    }

    private void openCamera() {
        currentPhotoUri = createImageUri();
        if (currentPhotoUri != null) takePictureLauncher.launch(currentPhotoUri);
    }

    private Uri createImageUri() {
        try {
            File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            File image = File.createTempFile("IMG_", ".jpg", storageDir);
            return FileProvider.getUriForFile(requireContext(), "com.kbs.kbsintranett.fileprovider", image);
        } catch (IOException e) { return null; }
    }

    private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
        if (isChild) childFileUploads.put(fieldId, uri);
        else fileUploads.put(fieldId, uri);
        View view = (isChild ? childInputViews : inputViews).get(fieldId);
        if (view instanceof Button) {
            TextView txtView = (TextView) view.getTag();
            if (txtView != null) txtView.setText(getFileName(uri));
        }
    }

    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);
                }
            }
        }
        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());
        return m.find() ? m.group(2) : title;
    }

    private void renderTimeField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        EditText timeInput = new EditText(getContext());
        timeInput.setFocusable(false);
        timeInput.setHint("00:00");
        timeInput.setOnClickListener(v -> {
            Calendar c = Calendar.getInstance();
            new TimePickerDialog(getContext(), (tp, h, m) -> {
                timeInput.setText(String.format("%02d:%02d", h, m));
                evaluateAllConditionalLogic();
            }, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.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());
        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);

        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")) input.setText(user.getUserDisplayName());
        }
        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(); }
        });
        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.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
        input.setMinLines(3);
        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 -> evaluateAllConditionalLogic());
                group.addView(rb);
            }
        }
        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());
        List<String> labels = new ArrayList<>();
        labels.add("- Velg -");
        if (field.choices != null) { for (GravityField.Choice c : field.choices) labels.add(c.text); }
        spinner.setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, labels));
        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());
        checkBox.setText(field.checkboxLabel != null ? field.checkboxLabel : field.label);
        String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
        checkBox.setOnCheckedChangeListener((b, c) -> 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 (GravityField inputDef : field.inputs) {
                CheckBox cb = new CheckBox(getContext());
                cb.setText(inputDef.label);
                cb.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
                container.addView(cb);
                views.put(inputDef.id, cb);
            }
        }
    }

    private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
        EditText dateInput = new EditText(getContext());
        dateInput.setFocusable(false);
        dateInput.setHint("dd.mm.yyyy");
        dateInput.setOnClickListener(v -> {
            Calendar c = Calendar.getInstance();
            new DatePickerDialog(getContext(), (view, y, m, d) -> {
                dateInput.setText(String.format("%02d.%02d.%d", d, m + 1, y));
                evaluateAllConditionalLogic();
            }, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH)).show();
        });
        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) {
        if (parentField.inputs == null) return;
        for (GravityField subField : parentField.inputs) {
            TextView subLabel = new TextView(getContext());
            subLabel.setText(subField.label + (parentField.isRequired ? " *" : ""));
            subLabel.setTextSize(12);
            container.addView(subLabel);
            EditText subInput = new EditText(getContext());
            container.addView(subInput);
            views.put(subField.id, subInput);
            req.put(subField.id, parentField.isRequired);
        }
    }

    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);
            container.addView(desc);
        }
        View line = new View(getContext());
        line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 2));
        line.setBackgroundColor(Color.LTGRAY);
        container.addView(line);
    }

    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);
            setViewVisibility(field.id, (show && isMatch) || (!show && !isMatch));
        }
    }

    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 &= ruleMatch; if (!aggregatedResult) break; }
            else { aggregatedResult |= ruleMatch; if (aggregatedResult) break; }
        }
        return aggregatedResult;
    }

    private boolean checkRule(String actual, String op, String target) {
        if (actual == null) actual = ""; if (target == null) target = "";
        switch (op.toLowerCase()) {
            case "is": return actual.equalsIgnoreCase(target);
            case "isnot": return !actual.equalsIgnoreCase(target);
            case "contains": return actual.toLowerCase().contains(target.toLowerCase());
            default: return false;
        }
    }

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

    private String getInputValueGeneric(View view) {
        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) return ((Spinner) view).getSelectedItemPosition() > 0 ? ((Spinner) view).getSelectedItem().toString() : "";
        if (view instanceof CheckBox) return ((CheckBox) view).isChecked() ? "1" : "";
        return "";
    }

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

    private void submitDynamicForm() {
        JSONObject inputValues = new JSONObject();
        boolean hasValues = false;
        for (Map.Entry<String, View> entry : inputViews.entrySet()) {
            View wrapper = fieldWrappers.get(entry.getKey());
            if (wrapper != null && wrapper.getVisibility() != View.VISIBLE) continue;
            String val = getInputValueGeneric(entry.getValue());
            if (requiredFieldsMap.getOrDefault(entry.getKey(), false) && val.isEmpty() && !(entry.getValue() instanceof Button)) {
                Toast.makeText(getContext(), "Fyll ut påkrevde felt", Toast.LENGTH_SHORT).show();
                return;
            }
            if (!val.isEmpty()) {
                try { inputValues.put("input_" + entry.getKey(), val); hasValues = true; } catch (JSONException ignored) {}
            }
        }
        if (!hasValues && fileUploads.isEmpty()) return;
        updateStatus("Sender inn...");
        if (!fileUploads.isEmpty()) sendMultipart(inputValues);
        else {
            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", UserManager.getInstance().getCookie()).build();
            client.newCall(request).enqueue(new okhttp3.Callback() {
                @Override public void onResponse(okhttp3.Call call, Response response) {
                    if (response.isSuccessful() && getActivity() != null) getActivity().runOnUiThread(() -> { Toast.makeText(getContext(), "Sendt!", Toast.LENGTH_LONG).show(); clearInputs(); fetchFormEntries(); });
                }
                @Override public void onFailure(okhttp3.Call call, IOException e) {}
            });
        }
    }

    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>() {
                @Override public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
                    if (response.isSuccessful() && getActivity() != null) getActivity().runOnUiThread(() -> { Toast.makeText(getContext(), "Sendt!", Toast.LENGTH_LONG).show(); clearInputs(); fetchFormEntries(); });
                }
                @Override public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) {}
            });
        } catch (Exception ignored) {}
    }

    private MultipartBody.Part getFilePart(String partName, Uri uri) {
        try {
            InputStream is = getContext().getContentResolver().openInputStream(uri);
            String fileName = getFileName(uri);
            RequestBody rb = 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(is)) { sink.writeAll(source); } }
            };
            return MultipartBody.Part.createFormData(partName, fileName, rb);
        } catch (Exception e) { return null; }
    }

    private void fetchFormEntries() {
        UserManager user = UserManager.getInstance();
        String searchJson = "{\"field_filters\":[{\"key\":\"created_by\",\"value\":\"" + user.getUserId() + "\"}]}";
        String encodedSearch = "";
        try { encodedSearch = URLEncoder.encode(searchJson, "UTF-8"); } catch (Exception ignored) {}
        String url = BASE_URL_GF + "/entries?form_ids=" + formId + "&search=" + encodedSearch;
        Request req = new Request.Builder().url(url).header("Cookie", user.getCookie()).build();
        client.newCall(req).enqueue(new okhttp3.Callback() {
            @Override public void onResponse(okhttp3.Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    try {
                        JSONObject json = new JSONObject(response.body().string());
                        if (json.has("entries") && getActivity() != null) {
                            JSONArray entries = json.getJSONArray("entries");
                            getActivity().runOnUiThread(() -> showHistory(entries));
                        }
                    } catch (Exception ignored) {}
                }
            }
            @Override public void onFailure(okhttp3.Call call, IOException e) {}
        });
    }

    private void showHistory(JSONArray entries) {
        if (historyContainer == null) return; historyContainer.removeAllViews();
        lblHistory.setVisibility(entries.length() > 0 ? View.VISIBLE : View.GONE);
        try {
            for (int i = 0; i < Math.min(entries.length(), 10); i++) {
                JSONObject entry = entries.getJSONObject(i);
                TextView item = new TextView(getContext());
                item.setText("Innsendt: " + entry.optString("date_created"));
                item.setPadding(10, 20, 10, 20);
                item.setOnClickListener(v -> showEntryDetails(entry));
                historyContainer.addView(item);
            }
        } catch (Exception ignored) {}
    }

    private void showEntryDetails(JSONObject entry) {
        StringBuilder sb = new StringBuilder();
        sb.append("<b>Innsendt:</b> ").append(entry.optString("date_created")).append("<br><br>");
        // Enkel visning av feltverdier
        JSONArray keys = entry.names();
        if (keys != null) {
            for (int i = 0; i < keys.length(); i++) {
                String key = keys.optString(i);
                if (key.matches("\\d+")) sb.append("Felt ").append(key).append(": ").append(entry.optString(key)).append("<br>");
            }
        }
        new AlertDialog.Builder(getContext()).setTitle("Detaljer").setMessage(Html.fromHtml(sb.toString(), Html.FROM_HTML_MODE_COMPACT)).setPositiveButton("Lukk", null).show();
    }

    private void clearInputs() {
        for (View v : inputViews.values()) {
            if (v instanceof EditText) ((EditText) v).setText("");
            else if (v instanceof CheckBox) ((CheckBox) v).setChecked(false);
            else if (v instanceof RadioGroup) ((RadioGroup) v).clearCheck();
        }
        fileUploads.clear();
        nestedEntries.clear();
        if (nestedEntriesContainer != null) nestedEntriesContainer.removeAllViews();
    }

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

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (getActivity() instanceof AppCompatActivity) {
            AppCompatActivity activity = (AppCompatActivity) getActivity();
            if (activity.getSupportActionBar() != null) activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
    }

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