using System.Text.Json;
using JobsMedical.Web.Models;

namespace JobsMedical.Web.Services;

/// <summary>
/// Builds schema.org JSON-LD for listings so Google surfaces them as rich results
/// (Google for Jobs uses JobPosting). System.Text.Json guarantees valid, script-safe
/// output (Persian + &lt; &gt; &amp; are \u-escaped), so it can be emitted inside a
/// &lt;script type="application/ld+json"&gt; tag directly.
/// </summary>
public static class SeoJsonLd
{
    private static readonly JsonSerializerOptions Opts = new()
    {
        DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
    };

    public static string ShiftPosting(Shift s, string baseUrl)
    {
        var typeLabel = s.ShiftType switch
        {
            ShiftType.Day => "شیفت صبح",
            ShiftType.Evening => "شیفت عصر",
            ShiftType.Night => "شیفت شب",
            _ => "آنکال",
        };
        object? salary = s.PayAmount is long amt && amt > 0
            ? new { type = "MonetaryAmount", currency = "IRR", value = new { type = "QuantitativeValue", value = amt, unitText = "DAY" } }
            : null;

        var obj = new Dictionary<string, object?>
        {
            ["@context"] = "https://schema.org/",
            ["@type"] = "JobPosting",
            ["title"] = $"{s.Role?.Name} — {typeLabel}",
            ["description"] = string.IsNullOrWhiteSpace(s.Description)
                ? $"{typeLabel} برای {s.Role?.Name} در {s.Facility?.Name}، {s.Facility?.City?.Name}." : s.Description,
            ["datePosted"] = s.CreatedAt.ToString("yyyy-MM-dd"),
            ["validThrough"] = s.Date.ToString("yyyy-MM-dd"),
            ["employmentType"] = "PER_DIEM",
            ["directApply"] = true,
            ["identifier"] = new { type = "PropertyValue", name = "همکادر", value = $"shift-{s.Id}" },
            ["hiringOrganization"] = new { type = "Organization", name = s.Facility?.Name, sameAs = $"{baseUrl}/Facilities/Details/{s.FacilityId}" },
            ["jobLocation"] = new
            {
                type = "Place",
                address = new { type = "PostalAddress", addressLocality = s.Facility?.City?.Name, addressCountry = "IR", streetAddress = s.Facility?.Address }
            },
        };
        if (salary is not null) obj["baseSalary"] = salary;
        // rename "type" keys to "@type" after serialization (anonymous objects can't use @type directly)
        return Fix(JsonSerializer.Serialize(obj, Opts));
    }

    public static string JobPosting(JobOpening j, string baseUrl)
    {
        var empType = j.EmploymentType switch
        {
            EmploymentType.FullTime => "FULL_TIME",
            EmploymentType.PartTime => "PART_TIME",
            EmploymentType.Contract => "CONTRACTOR",
            _ => "OTHER",
        };
        long? min = j.SalaryMin, max = j.SalaryMax;
        object? salary = (min ?? max) is long
            ? new
            {
                type = "MonetaryAmount", currency = "IRR",
                value = new { type = "QuantitativeValue", minValue = min, maxValue = max ?? min, unitText = "MONTH" }
            }
            : null;

        var obj = new Dictionary<string, object?>
        {
            ["@context"] = "https://schema.org/",
            ["@type"] = "JobPosting",
            ["title"] = j.Title,
            ["description"] = string.IsNullOrWhiteSpace(j.Description)
                ? $"استخدام {j.Role?.Name} در {j.Facility?.Name}، {j.Facility?.City?.Name}." : j.Description,
            ["datePosted"] = j.CreatedAt.ToString("yyyy-MM-dd"),
            ["validThrough"] = j.CreatedAt.AddDays(30).ToString("yyyy-MM-dd"),
            ["employmentType"] = empType,
            ["directApply"] = true,
            ["identifier"] = new { type = "PropertyValue", name = "همکادر", value = $"job-{j.Id}" },
            ["hiringOrganization"] = new { type = "Organization", name = j.Facility?.Name, sameAs = $"{baseUrl}/Facilities/Details/{j.FacilityId}" },
            ["jobLocation"] = new
            {
                type = "Place",
                address = new { type = "PostalAddress", addressLocality = j.Facility?.City?.Name, addressCountry = "IR", streetAddress = j.Facility?.Address }
            },
        };
        if (salary is not null) obj["baseSalary"] = salary;
        return Fix(JsonSerializer.Serialize(obj, Opts));
    }

    public static string Organization(string baseUrl) => Fix(JsonSerializer.Serialize(new Dictionary<string, object?>
    {
        ["@context"] = "https://schema.org",
        ["@type"] = "Organization",
        ["name"] = "همکادر",
        ["url"] = baseUrl,
        ["logo"] = $"{baseUrl}/icons/icon-512.png",
        ["description"] = "سامانه یافتن شیفت و استخدام کادر درمان در ایران.",
    }, Opts));

    public static string WebSite(string baseUrl) => Fix(JsonSerializer.Serialize(new Dictionary<string, object?>
    {
        ["@context"] = "https://schema.org",
        ["@type"] = "WebSite",
        ["name"] = "همکادر",
        ["url"] = baseUrl,
        ["inLanguage"] = "fa-IR",
        ["potentialAction"] = new
        {
            type = "SearchAction",
            target = $"{baseUrl}/Shifts?q={{search_term_string}}",
            queryyy = "required name=search_term_string",
        },
    }, Opts));

    // Nested anonymous objects use "type"/"queryyy" placeholders for @type / query-input;
    // restore the @-prefixed schema.org keys here.
    private static string Fix(string json) => json
        .Replace("\"type\":", "\"@type\":")
        .Replace("\"queryyy\":", "\"query-input\":");
}
