// Copyright (C) 2025 Free Software Foundation, Inc.

// This file is part of GCC.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3.  If not see
// <http://www.gnu.org/licenses/>.

#include "rust-desugar-apit.h"
#include "rust-ast.h"
#include "rust-type.h"

namespace Rust {
namespace AST {

class DesugarApitType : public DefaultASTVisitor
{
  using DefaultASTVisitor::visit;

public:
  static std::pair<AST::Type *, std::vector<std::unique_ptr<GenericParam>>>
  Desugar (AST::Type &type)
  {
    DesugarApitType visitor (&type);
    type.accept_vis (visitor);
    rust_assert (visitor.translated != nullptr);
    return std::make_pair (visitor.translated,
			   std::move (visitor.implicit_generic_params));
  }

  // Generate a unique impl trait parameter name
  static Identifier get_impl_name ()
  {
    static size_t counter = 0;
    return Identifier ("Impl_" + std::to_string (counter++));
  }

  // these can hold other types
  void visit (AST::TupleType &tuple) override
  {
    for (auto &elem : tuple.get_elems ())
      {
	auto &type = *elem.get ();
	auto desugar = Desugar (type);
	auto tt = desugar.first;

	auto &implicit_generics = desugar.second;
	if (implicit_generics.empty ())
	  continue;

	if (tt != elem.get ())
	  elem = std::unique_ptr<Type> (tt);

	for (auto &implicit_generic : implicit_generics)
	  implicit_generic_params.push_back (std::move (implicit_generic));
      }
  }

  void visit (AST::ArrayType &type) override
  {
    auto &element_type = type.get_element_type ();
    auto desugar = Desugar (*element_type);
    auto tt = desugar.first;

    auto &implicit_generics = desugar.second;
    if (implicit_generics.empty ())
      return;

    if (tt != element_type.get ())
      element_type = std::unique_ptr<AST::Type> (tt);

    for (auto &implicit_generic : implicit_generics)
      implicit_generic_params.push_back (std::move (implicit_generic));
  }

  void visit (AST::ReferenceType &type) override
  {
    // Get a reference to the current type for in-place modification
    auto &referenced_type = type.get_type_referenced ();
    auto desugar = Desugar (referenced_type);
    auto tt = desugar.first;

    auto &implicit_generics = desugar.second;
    if (implicit_generics.empty ())
      return;

    // Update the reference type's contents rather than creating a new one
    if (&referenced_type != tt)
      {
	std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
	  static_cast<AST::TypeNoBounds *> (tt));
	type.get_type_ptr () = std::move (new_type_no_bounds);
      }

    // Collect all the implicit generic parameters we found
    for (auto &implicit_generic : implicit_generics)
      implicit_generic_params.push_back (std::move (implicit_generic));
  }

  void visit (AST::RawPointerType &type) override
  {
    auto &pointed_type = type.get_type_pointed_to ();
    auto desugar = Desugar (pointed_type);
    auto tt = desugar.first;

    auto &implicit_generics = desugar.second;
    if (implicit_generics.empty ())
      return;

    // Update the pointer's inner type directly using the new accessor
    if (&pointed_type != tt)
      {
	std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
	  static_cast<AST::TypeNoBounds *> (tt));
	type.get_type_ptr () = std::move (new_type_no_bounds);
      }

    // Collect all the implicit generic parameters we found
    for (auto &implicit_generic : implicit_generics)
      implicit_generic_params.push_back (std::move (implicit_generic));
  }

  void visit (AST::SliceType &type) override
  {
    auto &element_type = type.get_elem_type ();
    auto desugar = Desugar (element_type);
    auto tt = desugar.first;

    auto &implicit_generics = desugar.second;
    if (implicit_generics.empty ())
      return;

    if (&element_type != tt)
      {
	std::unique_ptr<AST::Type> new_elem_type (tt);
	type.get_elem_type_ptr () = std::move (new_elem_type);
      }

    // Collect all the implicit generic parameters we found
    for (auto &implicit_generic : implicit_generics)
      implicit_generic_params.push_back (std::move (implicit_generic));
  }

  void visit (AST::ParenthesisedType &type) override
  {
    auto &inner_type_ptr = type.get_type_in_parens ();
    auto desugar = Desugar (*inner_type_ptr);
    auto tt = desugar.first;

    auto &implicit_generics = desugar.second;
    if (implicit_generics.empty ())
      return;

    if (inner_type_ptr.get () != tt)
      {
	std::unique_ptr<AST::Type> new_inner_type (tt);
	inner_type_ptr = std::move (new_inner_type);
      }

    // Collect all the implicit generic parameters we found
    for (auto &implicit_generic : implicit_generics)
      implicit_generic_params.push_back (std::move (implicit_generic));
  }

  // this is where the desugar happens
  void visit (AST::ImplTraitType &type) override
  {
    // Generate a unique name using the static method
    auto ident = get_impl_name ();

    // Create a type path for the new generic parameter
    // Create a SimplePathSegment with the identifier string
    auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ());
    // Create a vector of SimplePathSegments for SimplePath constructor
    std::vector<SimplePathSegment> simple_segs = {simple_seg};
    // Create a SimplePath
    auto simple_path = SimplePath (simple_segs, false, type.get_locus ());

    // Convert to TypePath by creating path segments
    std::vector<std::unique_ptr<TypePathSegment>> segments;
    segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment (
      PathIdentSegment (ident.as_string (), type.get_locus ()), false,
      type.get_locus ())));

    // Create TypePath from segments
    auto type_path
      = new TypePath (std::move (segments), type.get_locus (), false);

    // Convert bounds from impl trait to generic parameter bounds
    std::vector<std::unique_ptr<TypeParamBound>> bounds;
    for (auto &bound : type.get_type_param_bounds ())
      bounds.push_back (bound->clone_type_param_bound ());

    // Create the new generic parameter
    auto generic_param = std::unique_ptr<TypeParam> (
      new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
		     true /*from impl trait*/));

    // Store the generic parameter to be added to the function signature
    implicit_generic_params.push_back (std::move (generic_param));

    // Replace impl trait with the new type parameter
    translated = type_path;
  }

  void visit (AST::ImplTraitTypeOneBound &type) override
  {
    // Generate a unique name using the static method
    auto ident = get_impl_name ();

    // Create a type path for the new generic parameter
    // Create a SimplePathSegment with the identifier string
    auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ());
    // Create a vector of SimplePathSegments for SimplePath constructor
    std::vector<SimplePathSegment> simple_segs = {simple_seg};
    // Create a SimplePath
    auto simple_path = SimplePath (simple_segs, false, type.get_locus ());

    // Convert to TypePath by creating path segments
    std::vector<std::unique_ptr<TypePathSegment>> segments;
    segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment (
      PathIdentSegment (ident.as_string (), type.get_locus ()), false,
      type.get_locus ())));

    // Create TypePath from segments
    auto type_path
      = new TypePath (std::move (segments), type.get_locus (), false);

    // Convert the bound to a generic parameter bound
    std::vector<std::unique_ptr<TypeParamBound>> bounds;
    bounds.push_back (std::move (type.get_trait_bound ()));

    // Create the new generic parameter
    auto generic_param = std::unique_ptr<TypeParam> (
      new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
		     true /*from impl trait*/));

    // Store the generic parameter to be added to the function signature
    implicit_generic_params.push_back (std::move (generic_param));

    // Replace impl trait with the new type parameter
    translated = type_path;
  }

private:
  DesugarApitType (AST::Type *base)
    : translated (base), implicit_generic_params ()
  {}

  AST::Type *translated;
  std::vector<std::unique_ptr<GenericParam>> implicit_generic_params;
};

// ---------

class ApitBoundProcessor
{
public:
  ApitBoundProcessor (
    WhereClause &where_clause,
    std::vector<std::unique_ptr<GenericParam>> &generic_params)
    : where_clause (where_clause), generic_params (generic_params)
  {}

  void go (std::vector<std::unique_ptr<GenericParam>> &implicit_generics)
  {
    // some desugars are more complex so imagine this case
    //
    // pub fn foo(_value: impl Bar<Baz = impl Foo>) -> i32 {
    //   15
    // }
    //
    // this needs to become:
    //
    // pub fn foo<T, U>(_value: T) -> i32
    // where
    //     T: Bar<Baz = U>,
    //     U: Foo,
    // {
    //     15
    // }
    //
    // so we need to walk all the implicit generics and the trait bounds paths
    // for more generics

    for (auto &implicit_generic : implicit_generics)
      {
	switch (implicit_generic->get_kind ())
	  {
	  case GenericParam::Kind::Type:
	    {
	      TypeParam &p
		= *static_cast<TypeParam *> (implicit_generic.get ());

	      process_type_param (p);
	      generic_params.push_back (std::move (implicit_generic));
	      for (auto &synth : synthetic_params)
		generic_params.push_back (std::move (synth));
	      synthetic_params.clear ();
	    }
	    break;

	  default:
	    generic_params.push_back (std::move (implicit_generic));
	    break;
	  }
      }
  }

private:
  void process_type_param (TypeParam &p)
  {
    auto &bounds = p.get_type_param_bounds ();
    std::vector<size_t> bounds_to_remove;
    for (size_t i = 0; i < bounds.size (); i++)
      {
	auto &tb = bounds[i];
	switch (tb->get_bound_type ())
	  {
	  case TypeParamBound::TypeParamBoundType::TRAIT:
	    {
	      TraitBound &ttb = *static_cast<TraitBound *> (tb.get ());
	      TypePath &path = ttb.get_type_path ();
	      bool deusgared = process_type_path (p, ttb, path);
	      if (deusgared)
		bounds_to_remove.push_back (i);
	    }

	  default:
	    break;
	  }
      }
    for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend ();
	 ++it)
      bounds.erase (bounds.begin () + *it);
  }

  bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path)
  {
    bool desugared = false;
    for (auto &segment : path.get_segments ())
      {
	switch (segment->get_type ())
	  {
	  case TypePathSegment::SegmentType::GENERIC:
	    {
	      TypePathSegmentGeneric &seg
		= *static_cast<TypePathSegmentGeneric *> (segment.get ());
	      desugared |= process_generic_segment (p, parent, path, seg);
	    }

	  default:
	    break;
	  }
      }
    return desugared;
  }

  bool process_generic_segment (TypeParam &p, TraitBound &parent,
				TypePath &path, TypePathSegmentGeneric &seg)
  {
    // we need to look for any impl types as default arguments in any generics
    // and remove this index from the generic arguments by using a where
    // constraint instead

    std::vector<std::unique_ptr<WhereClauseItem>> new_clauses;
    GenericArgs &generic_args = seg.get_generic_args ();
    std::vector<std::reference_wrapper<const GenericArgsBinding>>
      bindings_desugared;
    std::vector<GenericArgsBinding> &bindings
      = generic_args.get_binding_args ();

    for (auto &generic : bindings)
      {
	auto &t = generic.get_type ();
	auto translated = DesugarApitType::Desugar (t);
	auto tt = translated.first;

	auto &implicit_generics = translated.second;
	if (implicit_generics.empty ())
	  continue;

	if (tt != &t)
	  {
	    bindings_desugared.push_back (generic);
	    generic.get_type_ptr () = std::unique_ptr<Type> (tt);
	  }

	for (auto &implicit_generic : implicit_generics)
	  {
	    switch (implicit_generic->get_kind ())
	      {
	      case GenericParam::Kind::Type:
		{
		  TypeParam &tp
		    = *static_cast<TypeParam *> (implicit_generic.get ());

		  std::vector<std::unique_ptr<TypeParamBound>>
		    type_param_bounds;
		  for (auto &b : tp.get_type_param_bounds ())
		    type_param_bounds.push_back (std::move (b));
		  tp.get_type_param_bounds ().clear ();

		  // add synthetic parameter for this
		  synthetic_params.push_back (std::move (implicit_generic));

		  auto bound_type_path
		    = get_type_for_identifier (tp.get_type_representation ());

		  auto clause = new TypeBoundWhereClauseItem (
		    {}, std::move (bound_type_path),
		    std::move (type_param_bounds), tp.get_locus ());
		  std::unique_ptr<WhereClauseItem> clause_item
		    = std::unique_ptr<WhereClauseItem> (clause);
		  new_clauses.push_back (std::move (clause_item));
		}
		break;

	      default:
		synthetic_params.push_back (std::move (implicit_generic));
		break;
	      }
	  }
      }

    std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
    auto bound = std::unique_ptr<TypeParamBound> (new TraitBound (parent));
    type_param_bounds.push_back (std::move (bound));
    auto parent_type_path
      = get_type_for_identifier (p.get_type_representation ());
    auto clause
      = new TypeBoundWhereClauseItem ({}, std::move (parent_type_path),
				      std::move (type_param_bounds),
				      parent.get_locus ());
    std::unique_ptr<WhereClauseItem> clause_item
      = std::unique_ptr<WhereClauseItem> (clause);
    where_clause.get_items ().push_back (std::move (clause_item));

    for (auto &where_item : new_clauses)
      where_clause.get_items ().push_back (std::move (where_item));

    return !bindings_desugared.empty ();
  }

  static std::unique_ptr<Type> get_type_for_identifier (const Identifier &ident)
  {
    auto simple_seg
      = SimplePathSegment (ident.as_string (), ident.get_locus ());
    std::vector<SimplePathSegment> simple_segs = {simple_seg};
    auto simple_path = SimplePath (simple_segs, false, ident.get_locus ());
    std::vector<std::unique_ptr<TypePathSegment>> segments;
    segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment (
      PathIdentSegment (ident.as_string (), ident.get_locus ()), false,
      ident.get_locus ())));
    auto type_path = new TypePath (std::move (segments), ident.get_locus ());
    return std::unique_ptr<Type> (type_path);
  }

private:
  WhereClause &where_clause;
  std::vector<std::unique_ptr<GenericParam>> &generic_params;

  // mutates
  std::vector<std::unique_ptr<GenericParam>> synthetic_params;
};

// ---------

DesugarApit::DesugarApit () {}

void
DesugarApit::go (AST::Crate &crate)
{
  DefaultASTVisitor::visit (crate);
}

void
DesugarApit::visit (AST::Function &function)
{
  if (!function.has_function_params ())
    return;

  auto &fn_params = function.get_function_params ();
  for (auto &param : fn_params)
    {
      if (param->is_variadic () || param->is_self ())
	continue;

      auto *p = param.get ();
      auto &fp = *static_cast<AST::FunctionParam *> (p);
      auto &type = fp.get_type ();

      auto translated = DesugarApitType::Desugar (type);
      auto tt = translated.first;

      auto &implicit_generics = translated.second;
      if (implicit_generics.empty ())
	continue;

      if (fp.get_type_ptr ().get () != tt)
	{
	  fp.get_type_ptr () = std::unique_ptr<AST::Type> (tt);
	}

      ApitBoundProcessor processor (function.get_where_clause (),
				    function.get_generic_params ());
      processor.go (implicit_generics);
    }
}

} // namespace AST
} // namespace Rust
