<?php
/**
 * Export and import dish rows as CSV.
 *
 * @package Maca_Menu_List
 */

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Column delimiter for dish CSV export/import (semicolon — safe for commas in text and Swedish Excel).
 *
 * @return string
 */
function maca_menulist_dish_csv_delimiter() {
    return ';';
}

/**
 * Detect delimiter from the header line (supports legacy comma-separated files).
 *
 * @param string $header_line First line of the CSV (without BOM).
 * @return string
 */
function maca_menulist_dish_csv_detect_delimiter($header_line) {
    $semicolon = 0;
    $comma = 0;
    $in_quotes = false;
    $length = strlen($header_line);

    for ($i = 0; $i < $length; $i++) {
        $char = $header_line[ $i ];

        if ($char === '"') {
            if ($in_quotes && $i + 1 < $length && $header_line[ $i + 1 ] === '"') {
                ++$i;
                continue;
            }
            $in_quotes = ! $in_quotes;
            continue;
        }

        if (! $in_quotes) {
            if ($char === ';') {
                ++$semicolon;
            } elseif ($char === ',') {
                ++$comma;
            }
        }
    }

    if ($semicolon > 0 && $semicolon >= $comma) {
        return ';';
    }

    if ($comma > 0) {
        return ',';
    }

    return maca_menulist_dish_csv_delimiter();
}

/**
 * CSV column keys (stable for round-trip import/export).
 *
 * @return array<int, string>
 */
function maca_menulist_dish_csv_column_keys() {
    return array(
        'id',
        'category',
        'title',
        'title_en',
        'description',
        'description_en',
        'price',
        'price_takeaway',
        'takeaway_active',
        'vat_code',
        'image_url',
        'is_active',
        'allergens',
        'sort_order',
    );
}

/**
 * Human-readable CSV headers (English keys — same as column keys).
 *
 * @return array<int, string>
 */
function maca_menulist_dish_csv_headers() {
    return array(
        'id',
        'category',
        'title',
        'title_en',
        'description',
        'description_en',
        'price',
        'price_takeaway',
        'takeaway_active',
        'vat_code',
        'image_url',
        'is_active',
        'allergens',
        'sort_order',
    );
}

/**
 * Normalize a CSV header cell to a known column key.
 *
 * @param string $header Raw header.
 * @return string Empty when unknown.
 */
function maca_menulist_dish_csv_normalize_header($header) {
    $key = strtolower(trim((string) $header));
    $key = preg_replace('/[^a-z0-9_]+/', '_', $key);
    $key = trim((string) $key, '_');

    $aliases = array(
        'kategori' => 'category',
        'category_name' => 'category',
        'titel' => 'title',
        'titel_en' => 'title_en',
        'title_english' => 'title_en',
        'beskrivning' => 'description',
        'description_en' => 'description_en',
        'pris' => 'price',
        'takeaway_pris' => 'price_takeaway',
        'takeaway_price' => 'price_takeaway',
        'moms_kod' => 'vat_code',
        'momskod' => 'vat_code',
        'moms' => 'vat_code',
        'vat' => 'vat_code',
        'bild' => 'image_url',
        'image' => 'image_url',
        'aktiv' => 'is_active',
        'active' => 'is_active',
        'allergener' => 'allergens',
        'allergen' => 'allergens',
        'sortering' => 'sort_order',
        'sort' => 'sort_order',
    );

    if (isset($aliases[$key])) {
        return $aliases[$key];
    }

    $known = maca_menulist_dish_csv_column_keys();

    return in_array($key, $known, true) ? $key : '';
}

/**
 * Transient key for CSV import preview.
 *
 * @return string
 */
function maca_menulist_dish_csv_transient_key() {
    return 'maca_dish_csv_import_' . get_current_user_id();
}

/**
 * @return array<string, mixed>|null
 */
function maca_menulist_dish_csv_get_preview() {
    $data = get_transient(maca_menulist_dish_csv_transient_key());

    return is_array($data) ? $data : null;
}

/**
 * @param array<string, mixed> $data Preview payload.
 * @return void
 */
function maca_menulist_dish_csv_set_preview($data) {
    set_transient(maca_menulist_dish_csv_transient_key(), $data, HOUR_IN_SECONDS);
}

/**
 * @return void
 */
function maca_menulist_dish_csv_clear_preview() {
    delete_transient(maca_menulist_dish_csv_transient_key());
}

/**
 * Flash notice after redirect.
 *
 * @param string $message Message.
 * @param string $type success|error.
 * @return void
 */
function maca_menulist_dish_csv_flash_notice($message, $type = 'success') {
    set_transient(
        'maca_dish_csv_flash_' . get_current_user_id(),
        array(
            'message' => $message,
            'type' => $type,
        ),
        MINUTE_IN_SECONDS * 5
    );
}

/**
 * Show flash notice on admin screen.
 *
 * @return void
 */
function maca_menulist_dish_csv_show_flash_notice() {
    $flash = get_transient('maca_dish_csv_flash_' . get_current_user_id());

    if (!is_array($flash) || empty($flash['message'])) {
        return;
    }

    delete_transient('maca_dish_csv_flash_' . get_current_user_id());

    $type = isset($flash['type']) && $flash['type'] === 'error' ? 'error' : 'success';
    $level = $type === 'error' ? 'error' : 'updated';

    add_settings_error('maca_dish_csv', $type, $flash['message'], $level);
}

/**
 * Build export rows for all dishes.
 *
 * @return array<int, array<string, string>>
 */
function maca_menulist_dish_csv_build_export_rows() {
    $dishes = maca_menulist_db_get_dishes(false);
    $dish_ids = array_map(
        static function ($dish) {
            return (int) $dish->id;
        },
        $dishes
    );
    $allergens_by_dish = maca_menulist_db_get_allergens_for_dish_ids($dish_ids);
    $rows = array();

    foreach ($dishes as $dish) {
        $dish_id = (int) $dish->id;
        $allergen_names = array();

        if (!empty($allergens_by_dish[$dish_id])) {
            foreach ($allergens_by_dish[$dish_id] as $allergen) {
                $name = trim((string) ($allergen->name ?? ''));
                if ($name !== '') {
                    $allergen_names[] = $name;
                }
            }
        }

        $rows[] = array(
            'id' => (string) $dish_id,
            'category' => (string) ($dish->category_name ?? ''),
            'title' => (string) ($dish->title ?? ''),
            'title_en' => (string) ($dish->title_en ?? ''),
            'description' => (string) ($dish->description ?? ''),
            'description_en' => (string) ($dish->description_en ?? ''),
            'price' => $dish->price !== null && $dish->price !== '' ? number_format((float) $dish->price, 2, '.', '') : '',
            'price_takeaway' => $dish->price_takeaway !== null && $dish->price_takeaway !== '' ? number_format((float) $dish->price_takeaway, 2, '.', '') : '',
            'takeaway_active' => !empty($dish->takeaway_active) ? '1' : '0',
            'vat_code' => maca_menulist_sanitize_dish_vat_code($dish->vat_code ?? 'food'),
            'image_url' => (string) ($dish->image_url ?? ''),
            'is_active' => !empty($dish->is_active) ? '1' : '0',
            'allergens' => implode('; ', $allergen_names),
            'sort_order' => (string) (int) ($dish->sort_order ?? 0),
        );
    }

    return $rows;
}

/**
 * Stream dish CSV download.
 *
 * @return void
 */
function maca_menulist_dish_csv_emit_export() {
    $rows = maca_menulist_dish_csv_build_export_rows();
    $headers = maca_menulist_dish_csv_headers();
    $filename = 'maca-dishes-' . wp_date('Y-m-d') . '.csv';

    nocache_headers();
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename=' . $filename);

    $out = fopen('php://output', 'w');
    if ($out === false) {
        return;
    }

    $delimiter = maca_menulist_dish_csv_delimiter();

    fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF));
    fputcsv($out, $headers, $delimiter);

    foreach ($rows as $row) {
        $line = array();
        foreach ($headers as $key) {
            $line[] = isset($row[$key]) ? $row[$key] : '';
        }
        fputcsv($out, $line, $delimiter);
    }

    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- CSV stream to php://output.
    fclose($out);
    exit;
}

/**
 * Parse uploaded CSV into import rows.
 *
 * @param string $file_path Absolute path to CSV.
 * @return array<int, array<string, mixed>>|WP_Error
 */
function maca_menulist_dish_csv_parse_file($file_path) {
    if (!is_readable($file_path)) {
        return new WP_Error('maca_csv_unreadable', __('Kunde inte läsa CSV-filen.', 'maca-restu-pro'));
    }

    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- Uploaded CSV parse stream.
    $handle = fopen($file_path, 'r');
    if ($handle === false) {
        return new WP_Error('maca_csv_open', __('Kunde inte öppna CSV-filen.', 'maca-restu-pro'));
    }

    $first = fgets($handle);
    if ($first === false) {
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Uploaded CSV parse stream.
        fclose($handle);
        return new WP_Error('maca_csv_empty', __('CSV-filen är tom.', 'maca-restu-pro'));
    }

    if (strncmp($first, chr(0xEF) . chr(0xBB) . chr(0xBF), 3) === 0) {
        $first = substr($first, 3);
    }

    $delimiter = maca_menulist_dish_csv_detect_delimiter($first);

    rewind($handle);
    if (strncmp($first, chr(0xEF) . chr(0xBB) . chr(0xBF), 3) === 0) {
        fseek($handle, 3);
    }

    $header_row = fgetcsv($handle, 0, $delimiter, '"', '\\');
    if (!is_array($header_row) || empty($header_row)) {
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Uploaded CSV parse stream.
        fclose($handle);
        return new WP_Error('maca_csv_header', __('CSV-filen saknar rubrikrad.', 'maca-restu-pro'));
    }

    $column_map = array();
    foreach ($header_row as $index => $header) {
        $key = maca_menulist_dish_csv_normalize_header($header);
        if ($key !== '') {
            $column_map[(int) $index] = $key;
        }
    }

    if (!in_array('title', $column_map, true) && !in_array('title_en', $column_map, true)) {
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Uploaded CSV parse stream.
        fclose($handle);
        return new WP_Error(
            'maca_csv_columns',
            __('CSV-filen måste innehålla minst kolumnen title eller title_en.', 'maca-restu-pro')
        );
    }

    $rows = array();
    $line_number = 1;

    while (($data = fgetcsv($handle, 0, $delimiter, '"', '\\')) !== false) {
        ++$line_number;

        if ($data === array(null) || (count($data) === 1 && trim((string) $data[0]) === '')) {
            continue;
        }

        $row = array(
            'import' => true,
            'id' => '',
            'category' => '',
            'title' => '',
            'title_en' => '',
            'description' => '',
            'description_en' => '',
            'price' => '',
            'price_takeaway' => '',
            'takeaway_active' => '0',
            'vat_code' => 'food',
            'image_url' => '',
            'is_active' => '1',
            'allergens' => '',
            'sort_order' => '',
            '_line' => $line_number,
        );

        $has_value = false;

        foreach ($column_map as $index => $key) {
            $value = isset($data[$index]) ? trim((string) $data[$index]) : '';
            if ($value === '') {
                continue;
            }

            $has_value = true;
            $row[$key] = $value;
        }

        if (!$has_value) {
            continue;
        }

        if (trim((string) $row['title']) === '' && trim((string) $row['title_en']) === '') {
            continue;
        }

        $row['vat_code'] = maca_menulist_parse_dish_vat_code($row['vat_code'] ?? 'food');

        $rows[] = $row;
    }

    // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Uploaded CSV parse stream.
    fclose($handle);

    if (empty($rows)) {
        return new WP_Error('maca_csv_no_rows', __('Inga rättrader hittades i CSV-filen.', 'maca-restu-pro'));
    }

    return $rows;
}

/**
 * Parse yes/no style CSV booleans.
 *
 * @param mixed $value Raw value.
 * @param int   $default Default 0|1.
 * @return int
 */
function maca_menulist_dish_csv_parse_bool($value, $default = 0) {
    $raw = strtolower(trim((string) $value));

    if ($raw === '') {
        return (int) $default;
    }

    if (in_array($raw, array('1', 'yes', 'true', 'ja', 'y'), true)) {
        return 1;
    }

    if (in_array($raw, array('0', 'no', 'false', 'nej', 'n'), true)) {
        return 0;
    }

    return (int) $default;
}

/**
 * Resolve allergen names from a CSV cell to IDs.
 *
 * @param string              $raw Allergen names (; or , separated).
 * @param array<string, int>  $cache Name cache (by reference).
 * @return array<int, int>
 */
function maca_menulist_dish_csv_resolve_allergen_ids($raw, &$cache) {
    $raw = trim((string) $raw);

    if ($raw === '') {
        return array();
    }

    $parts = preg_split('/[;,]+/', $raw);
    if (!is_array($parts)) {
        return array();
    }

    $ids = array();

    foreach ($parts as $part) {
        $name = trim((string) $part);
        if ($name === '') {
            continue;
        }

        $key = mb_strtolower($name, 'UTF-8');
        if (isset($cache[$key])) {
            if ($cache[$key] > 0) {
                $ids[] = (int) $cache[$key];
            }
            continue;
        }

        $found = 0;
        foreach (maca_menulist_db_get_allergens() as $allergen) {
            $labels = array(
                trim((string) ($allergen->name ?? '')),
                trim((string) ($allergen->name_en ?? '')),
            );

            foreach ($labels as $label) {
                if ($label !== '' && mb_strtolower($label, 'UTF-8') === $key) {
                    $found = (int) $allergen->id;
                    break 2;
                }
            }
        }

        $cache[$key] = $found;
        if ($found > 0) {
            $ids[] = $found;
        }
    }

    return array_values(array_unique($ids));
}

/**
 * Import CSV rows into dish tables.
 *
 * @param array<int, array<string, mixed>> $rows Parsed rows.
 * @param array<string, bool>              $options create_categories, update_existing.
 * @return array{imported: int, updated: int, skipped: int, errors: array<int, string>}
 */
function maca_menulist_dish_csv_save_rows($rows, $options = array()) {
    $create_categories = !empty($options['create_categories']);
    $update_existing = !empty($options['update_existing']);

    $result = array(
        'imported' => 0,
        'updated' => 0,
        'skipped' => 0,
        'errors' => array(),
    );

    $category_cache = array();
    $allergen_cache = array();
    $sort_by_category = array();

    foreach ($rows as $index => $row) {
        if (empty($row['import'])) {
            ++$result['skipped'];
            continue;
        }

        $dish_id = isset($row['id']) ? intval($row['id']) : 0;
        $title = sanitize_text_field((string) ($row['title'] ?? ''));
        $title_en = sanitize_text_field((string) ($row['title_en'] ?? ''));
        $description = sanitize_textarea_field((string) ($row['description'] ?? ''));
        $description_en = sanitize_textarea_field((string) ($row['description_en'] ?? ''));
        $category_name = sanitize_text_field((string) ($row['category'] ?? ''));
        $price_raw = isset($row['price']) ? str_replace(',', '.', trim((string) $row['price'])) : '';
        $price = ($price_raw !== '') ? floatval($price_raw) : null;
        $price_takeaway_raw = isset($row['price_takeaway']) ? str_replace(',', '.', trim((string) $row['price_takeaway'])) : '';
        $price_takeaway = ($price_takeaway_raw !== '') ? floatval($price_takeaway_raw) : null;
        $takeaway_active = maca_menulist_dish_csv_parse_bool($row['takeaway_active'] ?? '', 0);
        $is_active = maca_menulist_dish_csv_parse_bool($row['is_active'] ?? '', 1);
        $vat_code = maca_menulist_parse_dish_vat_code($row['vat_code'] ?? 'food');
        $image_url = maca_menulist_normalize_url(esc_url_raw((string) ($row['image_url'] ?? '')));
        $allergen_ids = maca_menulist_dish_csv_resolve_allergen_ids((string) ($row['allergens'] ?? ''), $allergen_cache);

        if ($title === '' && $title_en === '') {
            $result['errors'][$index] = __('Rätttitel krävs.', 'maca-restu-pro');
            continue;
        }

        $existing = null;
        if ($dish_id > 0) {
            $existing = maca_menulist_db_get_dish($dish_id);
        }

        if ($existing && $update_existing) {
            $category_id = (int) $existing->category_id;

            if ($category_name !== '') {
                $resolved = maca_menulist_pdf_import_resolve_category_id($category_name, $create_categories, $category_cache);
                if ($resolved > 0) {
                    $category_id = $resolved;
                }
            }

            if ($category_id <= 0) {
                $result['errors'][$index] = __('Kunde inte matcha rättkategori.', 'maca-restu-pro');
                continue;
            }

            $sort_order = isset($row['sort_order']) && $row['sort_order'] !== ''
                ? intval($row['sort_order'])
                : (int) $existing->sort_order;

            $write = array(
                'category_id' => $category_id,
                'title' => $title,
                'title_en' => $title_en,
                'description' => $description,
                'description_en' => $description_en,
                'price' => $price,
                'price_takeaway' => $price_takeaway,
                'takeaway_active' => $takeaway_active,
                'vat_code' => $vat_code,
                'image_url' => $image_url !== '' ? $image_url : null,
                'sort_order' => $sort_order,
                'is_active' => $is_active,
            );

            if (maca_menulist_db_update_dish($dish_id, $write) === false) {
                $result['errors'][$index] = __('Databasfel vid uppdatering av rätt.', 'maca-restu-pro');
                continue;
            }

            maca_menulist_db_set_dish_allergens($dish_id, $allergen_ids);
            ++$result['updated'];
            continue;
        }

        if ($existing && !$update_existing) {
            ++$result['skipped'];
            continue;
        }

        $category_id = maca_menulist_pdf_import_resolve_category_id($category_name, $create_categories, $category_cache);

        if ($category_id <= 0) {
            $result['errors'][$index] = __('Kunde inte matcha rättkategori.', 'maca-restu-pro');
            continue;
        }

        if (isset($row['sort_order']) && $row['sort_order'] !== '') {
            $sort_order = intval($row['sort_order']);
        } else {
            if (!isset($sort_by_category[$category_id])) {
                global $wpdb;
                $dishes_table = maca_menulist_db_dishes_table();
                $max_sort = $wpdb->get_var(
                    $wpdb->prepare(
                        "SELECT MAX(sort_order) FROM $dishes_table WHERE category_id = %d",
                        $category_id
                    )
                );
                $sort_by_category[$category_id] = ($max_sort !== null && $max_sort !== '') ? (int) $max_sort : -1;
            }

            ++$sort_by_category[$category_id];
            $sort_order = $sort_by_category[$category_id];
        }

        $inserted = maca_menulist_db_insert_dish(
            array(
                'category_id' => $category_id,
                'title' => $title,
                'title_en' => $title_en,
                'description' => $description,
                'description_en' => $description_en,
                'price' => $price,
                'price_takeaway' => $price_takeaway,
                'takeaway_active' => $takeaway_active,
                'vat_code' => $vat_code,
                'image_url' => $image_url !== '' ? $image_url : null,
                'sort_order' => $sort_order,
                'is_active' => $is_active,
            )
        );

        if ($inserted === false) {
            $result['errors'][$index] = __('Databasfel vid sparning av rätt.', 'maca-restu-pro');
            continue;
        }

        global $wpdb;
        $saved_id = (int) $wpdb->insert_id;
        maca_menulist_db_set_dish_allergens($saved_id, $allergen_ids);
        ++$result['imported'];
    }

    return $result;
}
